Skip to content

Commit 6776fb1

Browse files
iritkatrielFidget-Spinner
authored andcommitted
pythongh-102828: emit deprecation warning for onerror arg to shutil.rmtree (python#102850)
1 parent 52172d3 commit 6776fb1

File tree

4 files changed

+28
-12
lines changed

4 files changed

+28
-12
lines changed

Doc/whatsnew/3.12.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,8 @@ shutil
339339

340340
* :func:`shutil.rmtree` now accepts a new argument *onexc* which is an
341341
error handler like *onerror* but which expects an exception instance
342-
rather than a *(typ, val, tb)* triplet. *onerror* is deprecated.
342+
rather than a *(typ, val, tb)* triplet. *onerror* is deprecated and
343+
will be removed in Python 3.14.
343344
(Contributed by Irit Katriel in :gh:`102828`.)
344345

345346

@@ -503,8 +504,8 @@ Deprecated
503504
fields are deprecated. Use :data:`sys.last_exc` instead.
504505
(Contributed by Irit Katriel in :gh:`102778`.)
505506

506-
* The *onerror* argument of :func:`shutil.rmtree` is deprecated. Use *onexc*
507-
instead. (Contributed by Irit Katriel in :gh:`102828`.)
507+
* The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed
508+
in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.)
508509

509510

510511
Pending Removal in Python 3.13
@@ -586,6 +587,9 @@ Pending Removal in Python 3.14
586587
functions that have been deprecated since Python 2 but only gained a
587588
proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14.
588589

590+
* The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12,
591+
and will be removed in 3.14.
592+
589593
Pending Removal in Future Versions
590594
----------------------------------
591595

Lib/shutil.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import fnmatch
1111
import collections
1212
import errno
13+
import warnings
1314

1415
try:
1516
import zlib
@@ -692,6 +693,11 @@ def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None):
692693
onerror is deprecated and only remains for backwards compatibility.
693694
If both onerror and onexc are set, onerror is ignored and onexc is used.
694695
"""
696+
697+
if onerror is not None:
698+
warnings.warn("onerror argument is deprecated, use onexc instead",
699+
DeprecationWarning)
700+
695701
sys.audit("shutil.rmtree", path, dir_fd)
696702
if ignore_errors:
697703
def onexc(*args):

Lib/tempfile.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -864,8 +864,8 @@ def __init__(self, suffix=None, prefix=None, dir=None,
864864

865865
@classmethod
866866
def _rmtree(cls, name, ignore_errors=False):
867-
def onerror(func, path, exc_info):
868-
if issubclass(exc_info[0], PermissionError):
867+
def onexc(func, path, exc):
868+
if isinstance(exc, PermissionError):
869869
def resetperms(path):
870870
try:
871871
_os.chflags(path, 0)
@@ -885,13 +885,13 @@ def resetperms(path):
885885
cls._rmtree(path, ignore_errors=ignore_errors)
886886
except FileNotFoundError:
887887
pass
888-
elif issubclass(exc_info[0], FileNotFoundError):
888+
elif isinstance(exc, FileNotFoundError):
889889
pass
890890
else:
891891
if not ignore_errors:
892892
raise
893893

894-
_shutil.rmtree(name, onerror=onerror)
894+
_shutil.rmtree(name, onexc=onexc)
895895

896896
@classmethod
897897
def _cleanup(cls, name, warn_message, ignore_errors=False):

Lib/test/test_shutil.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
unregister_unpack_format, get_unpack_formats,
2424
SameFileError, _GiveupOnFastCopy)
2525
import tarfile
26+
import warnings
2627
import zipfile
2728
try:
2829
import posix
@@ -207,7 +208,8 @@ def test_rmtree_fails_on_symlink_onerror(self):
207208
errors = []
208209
def onerror(*args):
209210
errors.append(args)
210-
shutil.rmtree(link, onerror=onerror)
211+
with self.assertWarns(DeprecationWarning):
212+
shutil.rmtree(link, onerror=onerror)
211213
self.assertEqual(len(errors), 1)
212214
self.assertIs(errors[0][0], os.path.islink)
213215
self.assertEqual(errors[0][1], link)
@@ -268,7 +270,8 @@ def test_rmtree_fails_on_junctions_onerror(self):
268270
errors = []
269271
def onerror(*args):
270272
errors.append(args)
271-
shutil.rmtree(link, onerror=onerror)
273+
with self.assertWarns(DeprecationWarning):
274+
shutil.rmtree(link, onerror=onerror)
272275
self.assertEqual(len(errors), 1)
273276
self.assertIs(errors[0][0], os.path.islink)
274277
self.assertEqual(errors[0][1], link)
@@ -337,7 +340,8 @@ def test_rmtree_errors_onerror(self):
337340
errors = []
338341
def onerror(*args):
339342
errors.append(args)
340-
shutil.rmtree(filename, onerror=onerror)
343+
with self.assertWarns(DeprecationWarning):
344+
shutil.rmtree(filename, onerror=onerror)
341345
self.assertEqual(len(errors), 2)
342346
self.assertIs(errors[0][0], os.scandir)
343347
self.assertEqual(errors[0][1], filename)
@@ -406,7 +410,8 @@ def test_on_error(self):
406410
self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
407411
self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
408412

409-
shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
413+
with self.assertWarns(DeprecationWarning):
414+
shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
410415
# Test whether onerror has actually been called.
411416
self.assertEqual(self.errorState, 3,
412417
"Expected call to onerror function did not happen.")
@@ -532,7 +537,8 @@ def onexc(*args):
532537
self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
533538
self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
534539

535-
shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc)
540+
with self.assertWarns(DeprecationWarning):
541+
shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc)
536542
self.assertTrue(onexc_called)
537543
self.assertFalse(onerror_called)
538544

0 commit comments

Comments
 (0)