Skip to content

Commit f212f21

Browse files
gh-152638: Deprecate tkinter.filedialog.askopenfiles() (GH-152647)
Opening several files at once is error-prone, and the returned list cannot be used in a "with" statement. Iterate over the names returned by askopenfilenames() and open them one by one instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b39dfe2 commit f212f21

6 files changed

Lines changed: 49 additions & 6 deletions

File tree

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/whatsnew/3.16.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,15 @@ New deprecations
671671
Use the new public :class:`tempfile.TemporaryFileWrapper` instead,
672672
which is the return type of :func:`tempfile.NamedTemporaryFile`.
673673

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+
674683
.. Add deprecations above alphabetically, not here at the end.
675684
676685
.. include:: ../deprecations/pending-removal-in-3.17.rst

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()

Lib/tkinter/filedialog.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,12 @@ def askopenfiles(mode = "r", **options):
575575
returns a list of open file objects or an empty list if
576576
cancel selected
577577
"""
578+
import warnings
579+
warnings._deprecated(
580+
"tkinter.filedialog.askopenfiles",
581+
message=f"{warnings._DEPRECATED_MSG}; iterate over the names returned "
582+
"by askopenfilenames() and open them instead",
583+
remove=(3, 19))
578584

579585
files = askopenfilenames(**options)
580586
return [open(filename, mode) for filename in files]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Deprecate :func:`tkinter.filedialog.askopenfiles`. Opening several files at
2+
once is error-prone and the returned list cannot be used in a :keyword:`with`
3+
statement; iterate over the names returned by
4+
:func:`tkinter.filedialog.askopenfilenames` and open them one by one instead.

0 commit comments

Comments
 (0)