]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-152638: Deprecate tkinter.filedialog.askopenfiles() (GH-152647)
authorSerhiy Storchaka <storchaka@gmail.com>
Sat, 11 Jul 2026 05:53:02 +0000 (08:53 +0300)
committerGitHub <noreply@github.com>
Sat, 11 Jul 2026 05:53:02 +0000 (05:53 +0000)
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>
Doc/deprecations/pending-removal-in-3.19.rst
Doc/library/dialog.rst
Doc/whatsnew/3.16.rst
Lib/test/test_tkinter/test_filedialog.py
Lib/tkinter/filedialog.py
Misc/NEWS.d/next/Library/2026-06-29-21-59-08.gh-issue-152638.92dpzo.rst [new file with mode: 0644]

index 4a58c606ab7596e5e18dbb508f47a6a9abf7638e..d7e0cd2d33ddb863ac4fc0fc9c915786b1549fd7 100644 (file)
@@ -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`.)
index 06f2d6ddbf4f48b525796f98f826848b07701e79..c18f2bb38b9ff1ddc3f8225c521a475d30a0a0f4 100644 (file)
@@ -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
index 3b614d69de26f0f962b50f3966bbb7c1e9650b8f..da98f1ad6b9bc3be41532bd7f9db0cbee4bcf59f 100644 (file)
@@ -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
index 817990a961e956eacd125922175d0fde6348a538..f65ed19895a1ed4310d6ffff76d285acda4e3d90 100644 (file)
@@ -203,5 +203,13 @@ class FileDialogTest(AbstractTkTest, unittest.TestCase):
         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()
index 29020475a3cb538993887389c5a05d87a03f27fd..5cf4959d3489fc8c6337133103434b25d53d2d32 100644 (file)
@@ -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 (file)
index 0000000..3fbffb0
--- /dev/null
@@ -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.