Skip to content

Commit

Permalink
Extract convenience wrapper of rmtree to setuptools._shutil for reuse
Browse files Browse the repository at this point in the history
  • Loading branch information
abravalheri committed Nov 11, 2024
1 parent e14cfec commit d9975c6
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 36 deletions.
41 changes: 41 additions & 0 deletions setuptools/_shutil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""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
except ImportError:
# 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:
log.debug("chmod failed: %s", e)


# Must match shutil._OnExcCallback
def _auto_chmod(func: Callable[..., _T], arg: str, exc: BaseException) -> _T:
"""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):
return py311.shutil_rmtree(path, ignore_errors, onexc)
39 changes: 3 additions & 36 deletions setuptools/command/easy_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from collections.abc import Iterable
from glob import glob
from sysconfig import get_path
from typing import TYPE_CHECKING, Callable, NoReturn, TypedDict, TypeVar
from typing import TYPE_CHECKING, NoReturn, TypedDict

from jaraco.text import yield_lines

Expand Down Expand Up @@ -63,7 +63,8 @@
from setuptools.wheel import Wheel

from .._path import ensure_directory
from ..compat import py39, py311, py312
from .._shutil import attempt_chmod_verbose as chmod, rmtree as _rmtree
from ..compat import py39, py312

from distutils import dir_util, log
from distutils.command import install
Expand All @@ -89,8 +90,6 @@
'get_exe_prefixes',
]

_T = TypeVar("_T")


def is_64bit():
return struct.calcsize("P") == 8
Expand Down Expand Up @@ -1789,16 +1788,6 @@ def _first_line_re():
return re.compile(first_line_re.pattern.decode())


# Must match shutil._OnExcCallback
def auto_chmod(func: Callable[..., _T], arg: str, exc: BaseException) -> _T:
"""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':
chmod(arg, stat.S_IWRITE)
return func(arg)
raise exc


def update_dist_caches(dist_path, fix_zipimporter_caches):
"""
Fix any globally cached `dist_path` related data
Expand Down Expand Up @@ -2021,24 +2010,6 @@ def is_python_script(script_text, filename):
return False # Not any Python I can recognize


try:
from os import (
chmod as _chmod, # pyright: ignore[reportAssignmentType] # Losing type-safety w/ pyright, but that's ok
)
except ImportError:
# Jython compatibility
def _chmod(*args: object, **kwargs: object) -> None: # type: ignore[misc] # Mypy reuses the imported definition anyway
pass


def chmod(path, mode):
log.debug("changing mode of %s to %o", path, mode)
try:
_chmod(path, mode)
except OSError as e:
log.debug("chmod failed: %s", e)


class _SplitArgs(TypedDict, total=False):
comments: bool
posix: bool
Expand Down Expand Up @@ -2350,10 +2321,6 @@ def load_launcher_manifest(name):
return manifest.decode('utf-8') % vars()


def _rmtree(path, ignore_errors: bool = False, onexc=auto_chmod):
return py311.shutil_rmtree(path, ignore_errors, onexc)


def current_umask():
tmp = os.umask(0o022)
os.umask(tmp)
Expand Down

0 comments on commit d9975c6

Please sign in to comment.