From 9dbd12375561a393eaec4b21ee4ac568a407cdb0 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 20 Aug 2024 20:39:24 -0400 Subject: gh-123084: Turn `shutil.ExecError` into a deprecated alias of `RuntimeError` (#123125) --- Doc/deprecations/pending-removal-in-3.16.rst | 5 +++++ Lib/shutil.py | 16 +++++++++++++--- Lib/test/test_shutil.py | 4 +++- .../2024-08-18-08-25-32.gh-issue-123084.rf8izX.rst | 4 ++++ 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-08-18-08-25-32.gh-issue-123084.rf8izX.rst diff --git a/Doc/deprecations/pending-removal-in-3.16.rst b/Doc/deprecations/pending-removal-in-3.16.rst index 10cb5e4..de134f8 100644 --- a/Doc/deprecations/pending-removal-in-3.16.rst +++ b/Doc/deprecations/pending-removal-in-3.16.rst @@ -8,3 +8,8 @@ Pending Removal in Python 3.16 * :mod:`symtable`: Deprecate :meth:`symtable.Class.get_methods` due to the lack of interest. (Contributed by Bénédikt Tran in :gh:`119698`.) + +* :mod:`shutil`: Deprecate :class:`!shutil.ExecError`, which hasn't + been raised by any :mod:`!shutil` function since Python 3.4. It's + now an alias for :exc:`RuntimeError`. + diff --git a/Lib/shutil.py b/Lib/shutil.py index 72b2d83..6037092 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -56,7 +56,7 @@ _WIN_DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC" __all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", "copytree", "move", "rmtree", "Error", "SpecialFileError", - "ExecError", "make_archive", "get_archive_formats", + "make_archive", "get_archive_formats", "register_archive_format", "unregister_archive_format", "get_unpack_formats", "register_unpack_format", "unregister_unpack_format", "unpack_archive", @@ -74,8 +74,6 @@ class SpecialFileError(OSError): """Raised when trying to do a kind of operation (e.g. copying) which is not supported on a special file (e.g. a named pipe)""" -class ExecError(OSError): - """Raised when a command could not be executed""" class ReadError(OSError): """Raised when an archive cannot be read""" @@ -1582,3 +1580,15 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): if _access_check(name, mode): return name return None + +def __getattr__(name): + if name == "ExecError": + import warnings + warnings._deprecated( + "shutil.ExecError", + f"{warnings._DEPRECATED_MSG}; it " + "isn't raised by any shutil function.", + remove=(3, 16) + ) + return RuntimeError + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index c770be2..80e1d73 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -3393,7 +3393,7 @@ class PublicAPITests(unittest.TestCase): self.assertTrue(hasattr(shutil, '__all__')) target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat', 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error', - 'SpecialFileError', 'ExecError', 'make_archive', + 'SpecialFileError', 'make_archive', 'get_archive_formats', 'register_archive_format', 'unregister_archive_format', 'get_unpack_formats', 'register_unpack_format', 'unregister_unpack_format', @@ -3402,6 +3402,8 @@ class PublicAPITests(unittest.TestCase): if hasattr(os, 'statvfs') or os.name == 'nt': target_api.append('disk_usage') self.assertEqual(set(shutil.__all__), set(target_api)) + with self.assertWarns(DeprecationWarning): + from shutil import ExecError if __name__ == '__main__': diff --git a/Misc/NEWS.d/next/Library/2024-08-18-08-25-32.gh-issue-123084.rf8izX.rst b/Misc/NEWS.d/next/Library/2024-08-18-08-25-32.gh-issue-123084.rf8izX.rst new file mode 100644 index 0000000..eb01d66 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-08-18-08-25-32.gh-issue-123084.rf8izX.rst @@ -0,0 +1,4 @@ +Deprecate :class:`!shutil.ExecError`, which hasn't been +raised by any :mod:`shutil` function since Python 3.4. It's +now an alias for :exc:`RuntimeError`. + -- cgit v0.12