Skip to content

Commit 6e895a8

Browse files
Merge branch 'main' into clear_NameError_suggestion
2 parents 1a4c5e5 + d52cfd2 commit 6e895a8

23 files changed

Lines changed: 884 additions & 22 deletions

Doc/deprecations/pending-removal-in-3.19.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,11 @@ Pending removal in Python 3.19
4040
Before Python 3.14, this property was used to implement the corresponding
4141
``read()`` and ``readline()`` methods for :class:`~imaplib.IMAP4` but this
4242
is no longer the case since then.
43+
44+
* :mod:`tkinter`:
45+
46+
* :func:`tkinter.filedialog.askopenfiles` has been deprecated since Python
47+
3.16. Iterate over the names returned by
48+
:func:`~tkinter.filedialog.askopenfilenames` and open them one by one
49+
instead.
50+
(Contributed by Serhiy Storchaka in :gh:`152638`.)

Doc/library/dialog.rst

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,23 @@ cancelled it is the empty value documented for that function -- an empty
163163
string, an empty tuple, an empty list or ``None``.
164164

165165
.. function:: askopenfile(mode="r", **options)
166-
askopenfiles(mode="r", **options)
167166

168-
Create an :class:`Open` dialog.
169-
:func:`askopenfile` returns the opened file object, or ``None`` if the
170-
dialog is cancelled.
171-
:func:`askopenfiles` returns a list of the opened file objects, or an empty
172-
list if cancelled.
167+
Create an :class:`Open` dialog and return the opened file object,
168+
or ``None`` if the dialog is cancelled.
169+
The file is opened in mode *mode* (read-only ``'r'`` by default).
170+
171+
.. function:: askopenfiles(mode="r", **options)
172+
173+
Create an :class:`Open` dialog and return a list of the opened file objects,
174+
or an empty list if cancelled.
173175
The files are opened in mode *mode* (read-only ``'r'`` by default).
174176

177+
.. deprecated-removed:: next 3.19
178+
Opening several files at once is error-prone,
179+
and the returned list cannot be used in a :keyword:`with` statement.
180+
Iterate over the names returned by :func:`askopenfilenames`
181+
and open them one by one instead.
182+
175183
.. function:: asksaveasfile(mode="w", **options)
176184

177185
Create a :class:`SaveAs` dialog and return the opened file object, or

Doc/library/tk.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ alternative `GUI frameworks and tools <https://wiki.python.org/moin/GuiProgrammi
3333
tkinter.rst
3434
tkinter.colorchooser.rst
3535
tkinter.font.rst
36+
tkinter.fontchooser.rst
3637
dialog.rst
3738
tkinter.messagebox.rst
3839
tkinter.scrolledtext.rst
40+
tkinter.systray.rst
3941
tkinter.dnd.rst
4042
tkinter.ttk.rst
4143
idle.rst
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
:mod:`!tkinter.fontchooser` --- Font selection dialog
2+
=====================================================
3+
4+
.. module:: tkinter.fontchooser
5+
:synopsis: Font selection dialog
6+
7+
.. versionadded:: next
8+
9+
**Source code:** :source:`Lib/tkinter/fontchooser.py`
10+
11+
--------------
12+
13+
The :mod:`!tkinter.fontchooser` module provides the :class:`FontChooser` class
14+
as an interface to the native font selection dialog.
15+
16+
The font dialog is application-global:
17+
there is a single font dialog per Tcl interpreter,
18+
and all :class:`FontChooser` instances configure the same dialog.
19+
20+
Depending on the platform, the dialog may be modal or modeless,
21+
so :meth:`~FontChooser.show` may return immediately.
22+
The selected font is not returned:
23+
it is passed as a :class:`~tkinter.font.Font` object to the callback
24+
specified with the *command* option.
25+
26+
The dialog also generates two virtual events on the parent window
27+
(see the *parent* option):
28+
29+
``<<TkFontchooserVisibility>>``
30+
Generated when the dialog is shown or hidden.
31+
Query the *visible* option to tell which.
32+
33+
``<<TkFontchooserFontChanged>>``
34+
Generated when the selected font changes.
35+
36+
.. note::
37+
38+
The *command* callback is the only reliable way to obtain the selected font.
39+
On some platforms the *font* option is not updated to the user's choice.
40+
41+
.. class:: FontChooser(master=None, **options)
42+
43+
The class implementing the font selection dialog.
44+
45+
*master* is the widget whose Tcl interpreter owns the dialog.
46+
If omitted, it defaults to *parent* if that is given,
47+
or to the default root window otherwise.
48+
49+
The supported configuration options are:
50+
51+
* *parent* --- the window to which the dialog and its virtual events are related.
52+
It defaults to the main window;
53+
on macOS the dialog is shown as a sheet attached to it,
54+
rather than as a free-standing panel.
55+
* *title* --- the title of the dialog.
56+
* *font* --- the font that is currently selected in the dialog.
57+
* *command* --- a callback that is called
58+
with a :class:`~tkinter.font.Font` object wrapping the selected font
59+
when the user selects a font.
60+
* *visible* --- whether the dialog is currently displayed (read-only).
61+
62+
The *font* option accepts the forms supported by :class:`tkinter.font.Font`.
63+
64+
.. method:: configure(**options)
65+
config(**options)
66+
67+
Query or modify the options of the font dialog.
68+
With no arguments, return a dict of all option values.
69+
With a string argument, return the value of that option.
70+
Otherwise, set the given options.
71+
72+
.. method:: cget(option)
73+
74+
Return the value of the given option of the font dialog.
75+
76+
.. method:: show()
77+
78+
Display the font dialog.
79+
Depending on the platform, this method may return immediately
80+
or only once the dialog has been withdrawn.
81+
82+
.. method:: hide()
83+
84+
Hide the font dialog if it is displayed.
85+
86+
87+
.. seealso::
88+
89+
Module :mod:`tkinter.font`
90+
Tkinter font-handling utilities

Doc/library/tkinter.rst

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ The modules that provide Tk support include:
146146
:mod:`tkinter.font`
147147
Utilities to help work with fonts.
148148

149+
:mod:`tkinter.fontchooser`
150+
Dialog to let the user choose a font.
151+
149152
:mod:`tkinter.messagebox`
150153
Access to standard Tk dialog boxes.
151154

@@ -155,6 +158,9 @@ The modules that provide Tk support include:
155158
:mod:`tkinter.simpledialog`
156159
Basic dialogs and convenience functions.
157160

161+
:mod:`tkinter.systray`
162+
System tray icon and desktop notifications.
163+
158164
:mod:`tkinter.ttk`
159165
Themed widget set introduced in Tk 8.5, providing modern alternatives
160166
for many of the classic widgets in the main :mod:`!tkinter` module.
@@ -539,11 +545,8 @@ arguments, or by calling the :meth:`~Misc.keys` method on that widget.
539545
The return value of these calls is a dictionary whose key is the name of the
540546
option as a string (for example, ``'relief'``) and whose values are 5-tuples.
541547

542-
Some options, like ``bg`` are synonyms for common options with long names
543-
(``bg`` is shorthand for "background"). Passing the ``config()`` method the name
544-
of a shorthand option will return a 2-tuple, not 5-tuple. The 2-tuple passed
545-
back will contain the name of the synonym and the "real" option (such as
546-
``('bg', 'background')``).
548+
Some options, like ``bg``, are synonyms for common options with long names
549+
(``bg`` is shorthand for "background").
547550

548551
+-------+---------------------------------+--------------+
549552
| Index | Meaning | Example |
@@ -3555,6 +3558,13 @@ Widget classes
35553558
A newly created item is placed at the top of the list; the order can be
35563559
changed with :meth:`tag_raise` and :meth:`tag_lower`.
35573560

3561+
.. method:: tk_print()
3562+
3563+
Print the contents of the canvas using the native print dialog.
3564+
Requires Tk 8.7/9.0 or newer.
3565+
3566+
.. versionadded:: next
3567+
35583568
.. method:: create_arc(*args, **kw)
35593569
create_bitmap(*args, **kw)
35603570
create_image(*args, **kw)
@@ -4925,13 +4935,13 @@ Widget classes
49254935
containing *child*.
49264936
*option* may be any value allowed by :meth:`paneconfigure`.
49274937

4928-
.. method:: paneconfig(tagOrId, cnf=None, **kw)
4938+
.. method:: paneconfig(child, cnf=None, **kw)
49294939
:no-typesetting:
49304940

4931-
.. method:: paneconfigure(tagOrId, cnf=None, **kw)
4941+
.. method:: paneconfigure(child, cnf=None, **kw)
49324942

49334943
Query or modify the management options of the pane containing the widget
4934-
*tagOrId*.
4944+
*child*.
49354945
With no options, it returns a dictionary describing all of the available
49364946
options for the pane; given a single option name as a string, it returns
49374947
a description of that one option; otherwise it sets the given options.
@@ -4946,6 +4956,10 @@ Widget classes
49464956
``'always'``, ``'first'``, ``'last'``, ``'middle'`` or ``'never'``).
49474957
:meth:`paneconfig` is an alias of :meth:`!paneconfigure`.
49484958

4959+
.. deprecated-removed:: next 3.18
4960+
The first parameter was renamed from *tagOrId* to *child*.
4961+
The old name is still accepted as a keyword argument.
4962+
49494963
.. method:: identify(x, y)
49504964

49514965
Identify the panedwindow component underneath the point given by *x* and
@@ -5366,6 +5380,13 @@ Widget classes
53665380
to its base; several modifiers may be combined and are applied from left to
53675381
right, for example ``'insert wordstart - 1 c'``.
53685382

5383+
.. method:: tk_print()
5384+
5385+
Print the contents of the text widget using the native print dialog.
5386+
Requires Tk 8.7/9.0 or newer.
5387+
5388+
.. versionadded:: next
5389+
53695390
.. method:: insert(index, chars, *args)
53705391

53715392
Insert the string *chars* just before the character at *index* (if

Doc/library/tkinter.systray.rst

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
:mod:`!tkinter.systray` --- System tray icon and notifications
2+
==============================================================
3+
4+
.. module:: tkinter.systray
5+
:synopsis: System tray icon and desktop notifications
6+
7+
**Source code:** :source:`Lib/tkinter/systray.py`
8+
9+
.. versionadded:: next
10+
11+
--------------
12+
13+
The :mod:`!tkinter.systray` module provides the :class:`SysTrayIcon` class
14+
as an interface to the system tray (or taskbar) icon,
15+
and the :func:`notify` function which sends a desktop notification.
16+
They require Tk 8.7/9.0 or newer.
17+
18+
Only one system tray icon is supported per Tcl interpreter.
19+
20+
.. class:: SysTrayIcon(master=None, *, exists=False, **options)
21+
22+
The class implementing the system tray icon.
23+
24+
With *exists* false (the default), a new icon is created;
25+
creating a second one raises :exc:`~tkinter.TclError`.
26+
With *exists* true, the instance refers to the already-existing icon
27+
instead of creating one, reconfiguring it with any given options.
28+
29+
The supported configuration options are:
30+
31+
* *image* --- the image displayed in the system tray
32+
(required when creating an icon).
33+
On Windows, it must be a :class:`!PhotoImage`.
34+
* *text* --- the text displayed in the tooltip of the icon.
35+
* *button1* --- a callback that is called without arguments
36+
when the icon is clicked with the left mouse button.
37+
* *button3* --- a callback that is called without arguments
38+
when the icon is clicked with the right mouse button.
39+
40+
.. method:: configure(**options)
41+
config(**options)
42+
43+
Query or modify the options of the system tray icon.
44+
With no arguments, return a dict of all option values.
45+
With a string argument, return the value of that option.
46+
Otherwise, set the given options.
47+
48+
.. method:: cget(option)
49+
50+
Return the value of the given option of the system tray icon.
51+
52+
.. method:: exists()
53+
54+
Return whether the system tray icon exists.
55+
56+
.. method:: destroy()
57+
58+
Destroy the system tray icon.
59+
A new icon can be created afterwards.
60+
61+
.. method:: notify(title, message)
62+
63+
Send a desktop notification with the given title and message.
64+
65+
66+
.. function:: notify(title, message, *, master=None)
67+
68+
Send a desktop notification with the given title and message
69+
without creating a system tray icon first.
70+
On Windows, sending a notification requires an existing system
71+
tray icon, which is also displayed in the notification;
72+
use the :meth:`SysTrayIcon.notify` method instead.

Doc/whatsnew/3.16.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,11 @@ tkinter
406406
report the user idle time.
407407
(Contributed by Serhiy Storchaka in :gh:`151881`.)
408408

409+
* Added the :meth:`!tk_print` method to :class:`tkinter.Canvas` and
410+
:class:`tkinter.Text` which prints the contents of the widget using the
411+
native print dialog. It requires Tk 8.7/9.0 or newer.
412+
(Contributed by Serhiy Storchaka in :gh:`153256`.)
413+
409414
* Added new window-management methods :meth:`~tkinter.Misc.winfo_isdark`
410415
(dark mode detection), :meth:`~tkinter.Wm.wm_iconbadge` (application icon
411416
badge) and :meth:`~tkinter.Wm.wm_stackorder` (toplevel stacking order).
@@ -456,6 +461,12 @@ tkinter
456461
them.
457462
(Contributed by Serhiy Storchaka in :gh:`59396`.)
458463

464+
* Added the :mod:`tkinter.systray` module which provides the
465+
:class:`~tkinter.systray.SysTrayIcon` class as an interface to the system
466+
tray icon and the :func:`~tkinter.systray.notify` function which sends a
467+
desktop notification. They require Tk 8.7/9.0 or newer.
468+
(Contributed by Serhiy Storchaka in :gh:`153259`.)
469+
459470
* :class:`tkinter.scrolledtext.ScrolledText` gained a *use_ttk* parameter to use
460471
the themed :mod:`tkinter.ttk` frame and scroll bar instead of the classic
461472
:mod:`tkinter` widgets.
@@ -467,6 +478,11 @@ tkinter
467478
:meth:`~tkinter.font.Font.measure` and :meth:`~tkinter.font.Font.metrics`.
468479
(Contributed by Serhiy Storchaka in :gh:`143990`.)
469480

481+
* Added the :mod:`tkinter.fontchooser` module which provides the
482+
:class:`~tkinter.fontchooser.FontChooser` class as an interface to the
483+
native font selection dialog.
484+
(Contributed by Serhiy Storchaka in :gh:`72880`.)
485+
470486
* Values of several Tcl object types returned by :mod:`tkinter` are now
471487
converted to the corresponding Python type instead of being wrapped in a
472488
:class:`!_tkinter.Tcl_Obj`: ``index``, ``window``, ``nsName`` and
@@ -655,6 +671,15 @@ New deprecations
655671
Use the new public :class:`tempfile.TemporaryFileWrapper` instead,
656672
which is the return type of :func:`tempfile.NamedTemporaryFile`.
657673

674+
* :mod:`tkinter`:
675+
676+
* :func:`tkinter.filedialog.askopenfiles` is deprecated and slated for
677+
removal in Python 3.19. Opening several files at once is error-prone, and
678+
the returned list cannot be used in a :keyword:`with` statement. Iterate
679+
over the names returned by :func:`~tkinter.filedialog.askopenfilenames` and
680+
open them one by one instead.
681+
(Contributed by Serhiy Storchaka in :gh:`152638`.)
682+
658683
.. Add deprecations above alphabetically, not here at the end.
659684
660685
.. include:: ../deprecations/pending-removal-in-3.17.rst

Lib/test/test_asyncio/test_base_events.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,11 @@ async def sock_connect(sock, address):
10921092
await asyncio.sleep(1)
10931093
sock.connect(address)
10941094

1095-
loop = asyncio.new_event_loop()
1095+
# gh-151540: use a selector event loop instead of the platform
1096+
# default; the Windows proactor loop would register the mocked
1097+
# socket with a real IOCP handle instead of the mocked
1098+
# _add_reader/_add_writer below.
1099+
loop = asyncio.SelectorEventLoop()
10961100
loop._add_writer = mock.Mock()
10971101
loop._add_writer = mock.Mock()
10981102
loop._add_reader = mock.Mock()
@@ -1124,7 +1128,8 @@ async def sock_connect(sock, address):
11241128
await asyncio.sleep(1)
11251129
sock.connect(address)
11261130

1127-
loop = asyncio.new_event_loop()
1131+
# gh-151540: see test_create_connection_happy_eyeballs above.
1132+
loop = asyncio.SelectorEventLoop()
11281133
loop._add_writer = mock.Mock()
11291134
loop._add_writer = mock.Mock()
11301135
loop._add_reader = mock.Mock()

Lib/test/test_tkinter/test_filedialog.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,5 +203,13 @@ def test_type_ahead(self):
203203
self.assertEqual([d.files.get(i) for i in sel], ['charlie'])
204204

205205

206+
class DeprecationTest(unittest.TestCase):
207+
208+
def test_askopenfiles_deprecated(self):
209+
with swap_attr(filedialog, 'askopenfilenames', lambda **kw: ()):
210+
with self.assertWarns(DeprecationWarning):
211+
filedialog.askopenfiles()
212+
213+
206214
if __name__ == "__main__":
207215
unittest.main()

0 commit comments

Comments
 (0)