From: Serhiy Storchaka Date: Sat, 11 Jul 2026 05:53:02 +0000 (+0300) Subject: gh-152638: Deprecate tkinter.filedialog.askopenfiles() (GH-152647) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f212f219a508ff9c3601d7af39eca926462a9b80;p=thirdparty%2FPython%2Fcpython.git 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 --- diff --git a/Doc/deprecations/pending-removal-in-3.19.rst b/Doc/deprecations/pending-removal-in-3.19.rst index 4a58c606ab75..d7e0cd2d33dd 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 06f2d6ddbf4f..c18f2bb38b9f 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 3b614d69de26..da98f1ad6b9b 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 817990a961e9..f65ed19895a1 100644 --- a/Lib/test/test_tkinter/test_filedialog.py +++ b/Lib/test/test_tkinter/test_filedialog.py @@ -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() diff --git a/Lib/tkinter/filedialog.py b/Lib/tkinter/filedialog.py index 29020475a3cb..5cf4959d3489 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 000000000000..3fbffb03cb38 --- /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.