|
11 | 11 | import logging |
12 | 12 | logger = logging.getLogger(__name__) |
13 | 13 |
|
14 | | -# This function was copied from cpython, |
15 | | -# and changed to allow the base directory to be kept. |
16 | | -# Source: https://github.com/python/cpython/blob/v3.6.15/Lib/shutil.py#L451 |
17 | | -def rmtree(path, ignore_errors=False, onerror=None, keep_base_dir=False): |
| 14 | + |
| 15 | +def rmtree(path, *args, keep_base_dir=False, **kwargs): |
18 | 16 | """" |
19 | 17 | shutil.rmtree with the ability to keep the directory at `path`. Necessary for situations |
20 | 18 | when deleting the root directory would cause it to be unmounted. |
21 | 19 |
|
22 | 20 | Parameters |
23 | 21 | ---------- |
24 | | - path : str |
25 | | - Path to the directory with contents to remove |
26 | | - ignore_errors : bool, optional |
27 | | - If True, exceptions will not be raised when an error is encountered. Default: False |
28 | | - onerror : Callable, optional |
29 | | - Function to be called when an error is encountered. Only used if ignore_errors is False. |
30 | | - Default: None |
31 | 22 | keep_base_dir : bool, optional |
32 | 23 | If True, the base directory will remain while its children are deleted. Default: False |
| 24 | +
|
| 25 | + The rest of ``shutil.rmtree``'s parameters should be passed along. |
33 | 26 | """ |
34 | | - if ignore_errors: |
35 | | - def onerror(*args): |
36 | | - pass |
37 | | - elif onerror is None: |
38 | | - def onerror(*args): |
39 | | - raise |
40 | | - if shutil._use_fd_functions: |
41 | | - # While the unsafe rmtree works fine on bytes, the fd based does not. |
42 | | - if isinstance(path, bytes): |
43 | | - path = os.fsdecode(path) |
44 | | - # Note: To guard against symlink races, we use the standard |
45 | | - # lstat()/open()/fstat() trick. |
46 | | - try: |
47 | | - orig_st = os.lstat(path) |
48 | | - except Exception: |
49 | | - onerror(os.lstat, path, sys.exc_info()) |
50 | | - return |
51 | | - try: |
52 | | - fd = os.open(path, os.O_RDONLY) |
53 | | - except Exception: |
54 | | - onerror(os.lstat, path, sys.exc_info()) |
55 | | - return |
56 | | - try: |
57 | | - if os.path.samestat(orig_st, os.fstat(fd)): |
58 | | - shutil._rmtree_safe_fd(fd, path, onerror) |
59 | | - if not keep_base_dir: |
60 | | - try: |
61 | | - os.rmdir(path) |
62 | | - except OSError: |
63 | | - onerror(os.rmdir, path, sys.exc_info()) |
64 | | - else: |
65 | | - try: |
66 | | - # symlinks to directories are forbidden, see bug #1669 |
67 | | - raise OSError("Cannot call rmtree on a symbolic link") |
68 | | - except OSError: |
69 | | - onerror(os.path.islink, path, sys.exc_info()) |
70 | | - finally: |
71 | | - os.close(fd) |
| 27 | + if keep_base_dir == False: |
| 28 | + shutil.rmtree(path, *args, **kwargs) |
72 | 29 | else: |
73 | | - return _rmtree_unsafe(path, onerror, keep_base_dir) |
74 | | - |
75 | | - |
76 | | -# version vulnerable to race conditions |
77 | | -def _rmtree_unsafe(path, onerror, keep_base_dir=False): |
78 | | - try: |
79 | | - if os.path.islink(path): |
80 | | - # symlinks to directories are forbidden, see bug #1669 |
81 | | - raise OSError("Cannot call rmtree on a symbolic link") |
82 | | - except OSError: |
83 | | - onerror(os.path.islink, path, sys.exc_info()) |
84 | | - # can't continue even if onerror hook returns |
85 | | - return |
86 | | - names = [] |
87 | | - try: |
88 | 30 | names = os.listdir(path) |
89 | | - except OSError: |
90 | | - onerror(os.listdir, path, sys.exc_info()) |
91 | | - for name in names: |
92 | | - fullname = os.path.join(path, name) |
93 | | - try: |
94 | | - mode = os.lstat(fullname).st_mode |
95 | | - except OSError: |
96 | | - mode = 0 |
97 | | - if stat.S_ISDIR(mode): |
98 | | - _rmtree_unsafe(fullname, onerror) |
99 | | - else: |
100 | | - try: |
101 | | - os.unlink(fullname) |
102 | | - except OSError: |
103 | | - onerror(os.unlink, fullname, sys.exc_info()) |
104 | | - if not keep_base_dir: |
105 | | - try: |
106 | | - os.rmdir(path) |
107 | | - except OSError: |
108 | | - onerror(os.rmdir, path, sys.exc_info()) |
| 31 | + for name in names: |
| 32 | + fullname = os.path.join(path, name) |
| 33 | + shutil.rmtree(fullname, *args, **kwargs) |
109 | 34 |
|
110 | 35 |
|
111 | 36 | def glob_files_with_extensions(directory, extensions, recursive=True): |
|
0 commit comments