File size: 1,578 Bytes
838f737 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
"""Convenience layer on top of stdlib's shutil and os"""
import os
import stat
from typing import Callable, TypeVar
from .compat import py311
from distutils import log
try:
from os import chmod # pyright: ignore[reportAssignmentType]
# Losing type-safety w/ pyright, but that's ok
except ImportError: # pragma: no cover
# Jython compatibility
def chmod(*args: object, **kwargs: object) -> None: # type: ignore[misc] # Mypy reuses the imported definition anyway
pass
_T = TypeVar("_T")
def attempt_chmod_verbose(path, mode):
log.debug("changing mode of %s to %o", path, mode)
try:
chmod(path, mode)
except OSError as e: # pragma: no cover
log.debug("chmod failed: %s", e)
# Must match shutil._OnExcCallback
def _auto_chmod(
func: Callable[..., _T], arg: str, exc: BaseException
) -> _T: # pragma: no cover
"""shutils onexc callback to automatically call chmod for certain functions."""
# Only retry for scenarios known to have an issue
if func in [os.unlink, os.remove] and os.name == 'nt':
attempt_chmod_verbose(arg, stat.S_IWRITE)
return func(arg)
raise exc
def rmtree(path, ignore_errors=False, onexc=_auto_chmod):
"""
Similar to ``shutil.rmtree`` but automatically executes ``chmod``
for well know Windows failure scenarios.
"""
return py311.shutil_rmtree(path, ignore_errors, onexc)
def rmdir(path, **opts):
if os.path.isdir(path):
rmtree(path, **opts)
def current_umask():
tmp = os.umask(0o022)
os.umask(tmp)
return tmp
|