Aluode/PerceptionLabPortable
0
1"""Convenience layer on top of stdlib's shutil and os"""2 3import os4import stat5from typing import Callable, TypeVar6 7from .compat import py3118 9from distutils import log10 11try:12 from os import chmod # pyright: ignore[reportAssignmentType]13 # Losing type-safety w/ pyright, but that's ok14except ImportError: # pragma: no cover15 # Jython compatibility16 def chmod(*args: object, **kwargs: object) -> None: # type: ignore[misc] # Mypy reuses the imported definition anyway17 pass18 19 20_T = TypeVar("_T")21 22 23def attempt_chmod_verbose(path, mode):24 log.debug("changing mode of %s to %o", path, mode)25 try:26 chmod(path, mode)27 except OSError as e: # pragma: no cover28 log.debug("chmod failed: %s", e)29 30 31# Must match shutil._OnExcCallback32def _auto_chmod(33 func: Callable[..., _T], arg: str, exc: BaseException34) -> _T: # pragma: no cover35 """shutils onexc callback to automatically call chmod for certain functions."""36 # Only retry for scenarios known to have an issue37 if func in [os.unlink, os.remove] and os.name == 'nt':38 attempt_chmod_verbose(arg, stat.S_IWRITE)39 return func(arg)40 raise exc41 42 43def rmtree(path, ignore_errors=False, onexc=_auto_chmod):44 """45 Similar to ``shutil.rmtree`` but automatically executes ``chmod``46 for well know Windows failure scenarios.47 """48 return py311.shutil_rmtree(path, ignore_errors, onexc)49 50 51def rmdir(path, **opts):52 if os.path.isdir(path):53 rmtree(path, **opts)54 55 56def current_umask():57 tmp = os.umask(0o022)58 os.umask(tmp)59 return tmp60 