Repository: pypa/pip
File: src/pip/_internal/utils/misc.py (Python)

Code before:
        # Windows can raise spurious ENOTEMPTY errors. See #6426.
        if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY:
            raise


def get_prog() -> str:
    try:
        prog = os.path.basename(sys.argv[0])
        if prog in ("__main__.py", "-c"):
            return f"{sys.executable} -m pip"
        else:
            return prog
    except (AttributeError, TypeError, IndexError):
        pass
    return "pip"


def bare_exc_to_onexc(exc_val: BaseException) -> ExcInfo:
    exc_ty = type(exc_val)
    tb = exc_val.__traceback__
    if tb is None:
        import inspect

        frame = inspect.currentframe()
        assert frame is not None
        tb = TracebackType(None, frame, frame.f_lasti, frame.f_lineno)
    return (exc_ty, exc_val, tb)


def extract_exc_info_arg(f: OnErr) -> OnExc:
    def g(fn: FunctionType, p: Path, e: BaseException) -> Any:
        info = bare_exc_to_onexc(e)
        return f(fn, p, info)

    return functools.update_wrapper(g, f)


# Retry every half second for up to 3 seconds
# Tenacity raises RetryError by default, explicitly raise the original exception
@retry(reraise=True, stop=stop_after_delay(3), wait=wait_fixed(0.5))
def rmtree(
    dir: str,
    ignore_errors: bool = False,
    onexc: Optional[OnErr] = None,
) -> None:
    if ignore_errors:
        onexc = _onerror_ignore
    if onexc is None:
        onexc = _onerror_reraise
    handler: OnErr = partial(rmtree_errorhandler, onexc=onexc)
    if sys.version_info >= (3, 12):

Review comment (suggestion):
I wonder if we really need to go through this… I just cheked and it seems we never use the third argument (traceback) anywhere in the code base anyway. Maybe we should just always use the new signature (exception value only) and add a wrapper to drop the third argument for Python < 3.12 instead.

Code after:
        if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY:
            raise


def get_prog() -> str:
    try:
        prog = os.path.basename(sys.argv[0])
        if prog in ("__main__.py", "-c"):
            return f"{sys.executable} -m pip"
        else:
            return prog
    except (AttributeError, TypeError, IndexError):
        pass
    return "pip"


# Retry every half second for up to 3 seconds
# Tenacity raises RetryError by default, explicitly raise the original exception
@retry(reraise=True, stop=stop_after_delay(3), wait=wait_fixed(0.5))
def rmtree(
    dir: str,
    ignore_errors: bool = False,
    onexc: Optional[OnExc] = None,
) -> None:
    if ignore_errors:
        onexc = _onerror_ignore
    if onexc is None:
        onexc = _onerror_reraise
    handler: OnErr = partial(
        # `[func, path, Union[ExcInfo, BaseException]] -> Any` is equivalent to
        # `Union[([func, path, ExcInfo] -> Any), ([func, path, BaseException] -> Any)]`.
        cast(Union[OnExc, OnErr], rmtree_errorhandler),
        onexc=onexc,
    )
    if sys.version_info >= (3, 12):
        # See https://docs.python.org/3.12/whatsnew/3.12.html#shutil.
        shutil.rmtree(dir, onexc=handler)
    else:
        shutil.rmtree(dir, onerror=handler)


def _onerror_ignore(*_args: Any) -> None:
    pass


def _onerror_reraise(*_args: Any) -> None:
    raise


def rmtree_errorhandler(
    func: FunctionType,