summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>2023-03-21 11:08:46 (GMT)
committerGitHub <noreply@github.com>2023-03-21 11:08:46 (GMT)
commit7f760c2fca3dc5f46a518f5b7622783039bc8b7b (patch)
tree9569716a28604e4d9e6c00a7107d4d8168b6fa61
parent868490e32790eb1f1b44bbae2f12d480a23dbdac (diff)
downloadcpython-7f760c2fca3dc5f46a518f5b7622783039bc8b7b.zip
cpython-7f760c2fca3dc5f46a518f5b7622783039bc8b7b.tar.gz
cpython-7f760c2fca3dc5f46a518f5b7622783039bc8b7b.tar.bz2
gh-102828: emit deprecation warning for onerror arg to shutil.rmtree (#102850)
-rw-r--r--Doc/whatsnew/3.12.rst10
-rw-r--r--Lib/shutil.py6
-rw-r--r--Lib/tempfile.py8
-rw-r--r--Lib/test/test_shutil.py16
4 files changed, 28 insertions, 12 deletions
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index af52c7c..b7c956d 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -339,7 +339,8 @@ shutil
* :func:`shutil.rmtree` now accepts a new argument *onexc* which is an
error handler like *onerror* but which expects an exception instance
- rather than a *(typ, val, tb)* triplet. *onerror* is deprecated.
+ rather than a *(typ, val, tb)* triplet. *onerror* is deprecated and
+ will be removed in Python 3.14.
(Contributed by Irit Katriel in :gh:`102828`.)
@@ -503,8 +504,8 @@ Deprecated
fields are deprecated. Use :data:`sys.last_exc` instead.
(Contributed by Irit Katriel in :gh:`102778`.)
-* The *onerror* argument of :func:`shutil.rmtree` is deprecated. Use *onexc*
- instead. (Contributed by Irit Katriel in :gh:`102828`.)
+* The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed
+ in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.)
Pending Removal in Python 3.13
@@ -586,6 +587,9 @@ Pending Removal in Python 3.14
functions that have been deprecated since Python 2 but only gained a
proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14.
+* The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12,
+ and will be removed in 3.14.
+
Pending Removal in Future Versions
----------------------------------
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 89a7ac7..b057640 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -10,6 +10,7 @@ import stat
import fnmatch
import collections
import errno
+import warnings
try:
import zlib
@@ -692,6 +693,11 @@ def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None):
onerror is deprecated and only remains for backwards compatibility.
If both onerror and onexc are set, onerror is ignored and onexc is used.
"""
+
+ if onerror is not None:
+ warnings.warn("onerror argument is deprecated, use onexc instead",
+ DeprecationWarning)
+
sys.audit("shutil.rmtree", path, dir_fd)
if ignore_errors:
def onexc(*args):
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index bb18d60..cf06092 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -864,8 +864,8 @@ class TemporaryDirectory:
@classmethod
def _rmtree(cls, name, ignore_errors=False):
- def onerror(func, path, exc_info):
- if issubclass(exc_info[0], PermissionError):
+ def onexc(func, path, exc):
+ if isinstance(exc, PermissionError):
def resetperms(path):
try:
_os.chflags(path, 0)
@@ -885,13 +885,13 @@ class TemporaryDirectory:
cls._rmtree(path, ignore_errors=ignore_errors)
except FileNotFoundError:
pass
- elif issubclass(exc_info[0], FileNotFoundError):
+ elif isinstance(exc, FileNotFoundError):
pass
else:
if not ignore_errors:
raise
- _shutil.rmtree(name, onerror=onerror)
+ _shutil.rmtree(name, onexc=onexc)
@classmethod
def _cleanup(cls, name, warn_message, ignore_errors=False):
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 89d65af..1c0589c 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -23,6 +23,7 @@ from shutil import (make_archive,
unregister_unpack_format, get_unpack_formats,
SameFileError, _GiveupOnFastCopy)
import tarfile
+import warnings
import zipfile
try:
import posix
@@ -207,7 +208,8 @@ class TestRmTree(BaseTest, unittest.TestCase):
errors = []
def onerror(*args):
errors.append(args)
- shutil.rmtree(link, onerror=onerror)
+ with self.assertWarns(DeprecationWarning):
+ shutil.rmtree(link, onerror=onerror)
self.assertEqual(len(errors), 1)
self.assertIs(errors[0][0], os.path.islink)
self.assertEqual(errors[0][1], link)
@@ -268,7 +270,8 @@ class TestRmTree(BaseTest, unittest.TestCase):
errors = []
def onerror(*args):
errors.append(args)
- shutil.rmtree(link, onerror=onerror)
+ with self.assertWarns(DeprecationWarning):
+ shutil.rmtree(link, onerror=onerror)
self.assertEqual(len(errors), 1)
self.assertIs(errors[0][0], os.path.islink)
self.assertEqual(errors[0][1], link)
@@ -337,7 +340,8 @@ class TestRmTree(BaseTest, unittest.TestCase):
errors = []
def onerror(*args):
errors.append(args)
- shutil.rmtree(filename, onerror=onerror)
+ with self.assertWarns(DeprecationWarning):
+ shutil.rmtree(filename, onerror=onerror)
self.assertEqual(len(errors), 2)
self.assertIs(errors[0][0], os.scandir)
self.assertEqual(errors[0][1], filename)
@@ -406,7 +410,8 @@ class TestRmTree(BaseTest, unittest.TestCase):
self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
- shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
+ with self.assertWarns(DeprecationWarning):
+ shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
# Test whether onerror has actually been called.
self.assertEqual(self.errorState, 3,
"Expected call to onerror function did not happen.")
@@ -532,7 +537,8 @@ class TestRmTree(BaseTest, unittest.TestCase):
self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
- shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc)
+ with self.assertWarns(DeprecationWarning):
+ shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc)
self.assertTrue(onexc_called)
self.assertFalse(onerror_called)