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]