https://github.com/python/cpython/commit/9ee9f58747652764e1bdca0050daeeaea8a6b92d
commit: 9ee9f58747652764e1bdca0050daeeaea8a6b92d
branch: main
author: Stan Ulbrych <[email protected]>
committer: StanFromIreland <[email protected]>
date: 2026-05-15T18:54:05+01:00
summary:

gh-149567: Remove deprecated `shutil.ExecError` (#149568)

files:
A Misc/NEWS.d/next/Library/2026-05-08-16-44-20.gh-issue-149567.iiZKEj.rst
M Doc/whatsnew/3.16.rst
M Lib/shutil.py
M Lib/test/test_peepholer.py
M Lib/test/test_shutil.py

diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst
index 8c06628a082e76..cff0b8bbe32f0b 100644
--- a/Doc/whatsnew/3.16.rst
+++ b/Doc/whatsnew/3.16.rst
@@ -141,6 +141,13 @@ mimetypes
   :meth:`mimetypes.MimeTypes.add_type`.
   Undotted extensions now raise a :exc:`ValueError`.
 
+shutil
+------
+
+* The :exc:`!ExecError` exception which has been deprecated since Python 3.14.
+  It has not been used by any function in :mod:`!shutil` since Python 3.4.
+  (Contributed by Stan Ulbrych in :gh:`149567`.)
+
 symtable
 --------
 
@@ -161,6 +168,7 @@ sysconfig
 * The :func:`!sysconfig.expand_makefile_vars` function
   which has been deprecated since Python 3.14.
   Use the ``vars`` argument of :func:`sysconfig.get_paths` instead.
+  (Contributed by Stan Ulbrych in :gh:`149499`.)
 
 tarfile
 -------
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 45cbe4c855b462..cad9b570241f2c 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -1638,15 +1638,3 @@ 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_peepholer.py b/Lib/test/test_peepholer.py
index d44e61f25f7f55..61c4ec9b7d5b4a 100644
--- a/Lib/test/test_peepholer.py
+++ b/Lib/test/test_peepholer.py
@@ -1127,8 +1127,8 @@ def 
test_import_from_doesnt_clobber_load_fast_borrow(self):
         def f(self):
             if x: pass
             self.x
-            from shutil import ExecError
-            print(ExecError)
+            from heapq import heapify_max
+            print(heapify_max)
         self.assertInBytecode(f, "LOAD_FAST_BORROW", "self")
 
 class DirectCfgOptimizerTests(CfgOptimizationTestCase):
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 13a3487382dfcf..59cb319b0a95b5 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -3580,8 +3580,6 @@ def test_module_all_attribute(self):
         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  # noqa: F401
 
 
 if __name__ == '__main__':
diff --git 
a/Misc/NEWS.d/next/Library/2026-05-08-16-44-20.gh-issue-149567.iiZKEj.rst 
b/Misc/NEWS.d/next/Library/2026-05-08-16-44-20.gh-issue-149567.iiZKEj.rst
new file mode 100644
index 00000000000000..e30563df79b3bc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-05-08-16-44-20.gh-issue-149567.iiZKEj.rst
@@ -0,0 +1,2 @@
+Remove the :exc:`!shutil.ExecError` exception which has been deprecated
+since Python 3.14.

_______________________________________________
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