Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gh-102828: emit deprecation warning for onerror arg to shutil.rmtree #102850

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.)


Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
----------------------------------

Expand Down
6 changes: 6 additions & 0 deletions Lib/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import fnmatch
import collections
import errno
import warnings

try:
import zlib
Expand Down Expand Up @@ -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",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The warn call needs stacklevel=2 parameter so that the warning message shows what is making the deprecated call. Werkzeug's tests started failing on the latest 3.12 alpha because of this, and it's really hard to tell what's causing it (I think it's pytest) because the warning just points at this line right now instead of the caller.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, will fix.

DeprecationWarning)

sys.audit("shutil.rmtree", path, dir_fd)
if ignore_errors:
def onexc(*args):
Expand Down
8 changes: 4 additions & 4 deletions Lib/tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,8 +864,8 @@ def __init__(self, suffix=None, prefix=None, dir=None,

@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)
Expand All @@ -885,13 +885,13 @@ def resetperms(path):
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):
Expand Down
16 changes: 11 additions & 5 deletions Lib/test/test_shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
unregister_unpack_format, get_unpack_formats,
SameFileError, _GiveupOnFastCopy)
import tarfile
import warnings
import zipfile
try:
import posix
Expand Down Expand Up @@ -207,7 +208,8 @@ def test_rmtree_fails_on_symlink_onerror(self):
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)
Expand Down Expand Up @@ -268,7 +270,8 @@ def test_rmtree_fails_on_junctions_onerror(self):
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)
Expand Down Expand Up @@ -337,7 +340,8 @@ def test_rmtree_errors_onerror(self):
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)
Expand Down Expand Up @@ -406,7 +410,8 @@ def test_on_error(self):
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.")
Expand Down Expand Up @@ -532,7 +537,8 @@ def onexc(*args):
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)

Expand Down