https://github.com/python/cpython/commit/f212f219a508ff9c3601d7af39eca926462a9b80
commit: f212f219a508ff9c3601d7af39eca926462a9b80
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-11T05:53:02Z
summary:

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 <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-06-29-21-59-08.gh-issue-152638.92dpzo.rst
M Doc/deprecations/pending-removal-in-3.19.rst
M Doc/library/dialog.rst
M Doc/whatsnew/3.16.rst
M Lib/test/test_tkinter/test_filedialog.py
M Lib/tkinter/filedialog.py

diff --git a/Doc/deprecations/pending-removal-in-3.19.rst 
b/Doc/deprecations/pending-removal-in-3.19.rst
index 4a58c606ab7596e..d7e0cd2d33ddb86 100644
--- a/Doc/deprecations/pending-removal-in-3.19.rst
+++ b/Doc/deprecations/pending-removal-in-3.19.rst
@@ -40,3 +40,11 @@ Pending removal in Python 3.19
     Before Python 3.14, this property was used to implement the corresponding
     ``read()`` and ``readline()`` methods for :class:`~imaplib.IMAP4` but this
     is no longer the case since then.
+
+* :mod:`tkinter`:
+
+  * :func:`tkinter.filedialog.askopenfiles` has been deprecated since Python
+    3.16.  Iterate over the names returned by
+    :func:`~tkinter.filedialog.askopenfilenames` and open them one by one
+    instead.
+    (Contributed by Serhiy Storchaka in :gh:`152638`.)
diff --git a/Doc/library/dialog.rst b/Doc/library/dialog.rst
index 06f2d6ddbf4f48b..c18f2bb38b9ff1d 100644
--- a/Doc/library/dialog.rst
+++ b/Doc/library/dialog.rst
@@ -163,15 +163,23 @@ cancelled it is the empty value documented for that 
function -- an empty
 string, an empty tuple, an empty list or ``None``.
 
 .. function:: askopenfile(mode="r", **options)
-              askopenfiles(mode="r", **options)
 
-   Create an :class:`Open` dialog.
-   :func:`askopenfile` returns the opened file object, or ``None`` if the
-   dialog is cancelled.
-   :func:`askopenfiles` returns a list of the opened file objects, or an empty
-   list if cancelled.
+   Create an :class:`Open` dialog and return the opened file object,
+   or ``None`` if the dialog is cancelled.
+   The file is opened in mode *mode* (read-only ``'r'`` by default).
+
+.. function:: askopenfiles(mode="r", **options)
+
+   Create an :class:`Open` dialog and return a list of the opened file objects,
+   or an empty list if cancelled.
    The files are opened in mode *mode* (read-only ``'r'`` by default).
 
+   .. deprecated-removed:: next 3.19
+      Opening several files at once is error-prone,
+      and the returned list cannot be used in a :keyword:`with` statement.
+      Iterate over the names returned by :func:`askopenfilenames`
+      and open them one by one instead.
+
 .. function:: asksaveasfile(mode="w", **options)
 
    Create a :class:`SaveAs` dialog and return the opened file object, or
diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst
index 3b614d69de26f0f..da98f1ad6b9bc3b 100644
--- a/Doc/whatsnew/3.16.rst
+++ b/Doc/whatsnew/3.16.rst
@@ -671,6 +671,15 @@ New deprecations
     Use the new public :class:`tempfile.TemporaryFileWrapper` instead,
     which is the return type of :func:`tempfile.NamedTemporaryFile`.
 
+* :mod:`tkinter`:
+
+  * :func:`tkinter.filedialog.askopenfiles` is deprecated and slated for
+    removal in Python 3.19.  Opening several files at once is error-prone, and
+    the returned list cannot be used in a :keyword:`with` statement.  Iterate
+    over the names returned by :func:`~tkinter.filedialog.askopenfilenames` and
+    open them one by one instead.
+    (Contributed by Serhiy Storchaka in :gh:`152638`.)
+
 .. Add deprecations above alphabetically, not here at the end.
 
 .. include:: ../deprecations/pending-removal-in-3.17.rst
diff --git a/Lib/test/test_tkinter/test_filedialog.py 
b/Lib/test/test_tkinter/test_filedialog.py
index 817990a961e956e..f65ed19895a1ed4 100644
--- a/Lib/test/test_tkinter/test_filedialog.py
+++ b/Lib/test/test_tkinter/test_filedialog.py
@@ -203,5 +203,13 @@ def test_type_ahead(self):
         self.assertEqual([d.files.get(i) for i in sel], ['charlie'])
 
 
+class DeprecationTest(unittest.TestCase):
+
+    def test_askopenfiles_deprecated(self):
+        with swap_attr(filedialog, 'askopenfilenames', lambda **kw: ()):
+            with self.assertWarns(DeprecationWarning):
+                filedialog.askopenfiles()
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/Lib/tkinter/filedialog.py b/Lib/tkinter/filedialog.py
index 29020475a3cb538..5cf4959d3489fc8 100644
--- a/Lib/tkinter/filedialog.py
+++ b/Lib/tkinter/filedialog.py
@@ -575,6 +575,12 @@ def askopenfiles(mode = "r", **options):
     returns a list of open file objects or an empty list if
     cancel selected
     """
+    import warnings
+    warnings._deprecated(
+        "tkinter.filedialog.askopenfiles",
+        message=f"{warnings._DEPRECATED_MSG}; iterate over the names returned "
+                "by askopenfilenames() and open them instead",
+        remove=(3, 19))
 
     files = askopenfilenames(**options)
     return [open(filename, mode) for filename in files]
diff --git 
a/Misc/NEWS.d/next/Library/2026-06-29-21-59-08.gh-issue-152638.92dpzo.rst 
b/Misc/NEWS.d/next/Library/2026-06-29-21-59-08.gh-issue-152638.92dpzo.rst
new file mode 100644
index 000000000000000..3fbffb03cb38961
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-06-29-21-59-08.gh-issue-152638.92dpzo.rst
@@ -0,0 +1,4 @@
+Deprecate :func:`tkinter.filedialog.askopenfiles`.  Opening several files at
+once is error-prone and the returned list cannot be used in a :keyword:`with`
+statement; iterate over the names returned by
+:func:`tkinter.filedialog.askopenfilenames` and open them one by one instead.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to