Merge pull request #3079 from edgarrmondragon/deprecation-rmtree-onerror

Address deprecation warning in `shutil.rmtree(onerror=...)`
This commit is contained in:
Anthony Sottile 2023-12-09 14:59:09 -05:00 committed by GitHub
commit 23a2b7360e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 18 deletions

View file

@ -19,5 +19,5 @@ jobs:
main-linux: main-linux:
uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0 uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0
with: with:
env: '["py39", "py310", "py311"]' env: '["py39", "py310", "py311", "py312"]'
os: ubuntu-latest os: ubuntu-latest

View file

@ -202,24 +202,36 @@ else: # pragma: no cover
cmd_output_p = cmd_output_b cmd_output_p = cmd_output_b
def rmtree(path: str) -> None: def _handle_readonly(
"""On windows, rmtree fails for readonly dirs.""" func: Callable[[str], object],
def handle_remove_readonly( path: str,
func: Callable[..., Any], exc: OSError,
path: str, ) -> None:
exc: tuple[type[OSError], OSError, TracebackType], if (
func in (os.rmdir, os.remove, os.unlink) and
exc.errno in {errno.EACCES, errno.EPERM}
):
for p in (path, os.path.dirname(path)):
os.chmod(p, os.stat(p).st_mode | stat.S_IWUSR)
func(path)
else:
raise
if sys.version_info < (3, 12): # pragma: <3.12 cover
def _handle_readonly_old(
func: Callable[[str], object],
path: str,
excinfo: tuple[type[OSError], OSError, TracebackType],
) -> None: ) -> None:
excvalue = exc[1] return _handle_readonly(func, path, excinfo[1])
if (
func in (os.rmdir, os.remove, os.unlink) and def rmtree(path: str) -> None:
excvalue.errno in {errno.EACCES, errno.EPERM} shutil.rmtree(path, ignore_errors=False, onerror=_handle_readonly_old)
): else: # pragma: >=3.12 cover
for p in (path, os.path.dirname(path)): def rmtree(path: str) -> None:
os.chmod(p, os.stat(p).st_mode | stat.S_IWUSR) """On windows, rmtree fails for readonly dirs."""
func(path) shutil.rmtree(path, ignore_errors=False, onexc=_handle_readonly)
else:
raise
shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly)
def win_exe(s: str) -> str: def win_exe(s: str) -> str: