您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

54 行
1.5 KiB

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