This commit is contained in:
lz_db
2026-10-16 22:48:30 +08:00
parent 190de72571
commit 0b36fd3383
3161 changed files with 12787 additions and 77274 deletions
@@ -2,21 +2,17 @@
Monkey patching of distutils.
"""
from __future__ import annotations
import inspect
import platform
import sys
import types
from typing import TypeVar, cast, overload
import distutils.filelist
import platform
import types
import functools
from importlib import import_module
import inspect
_T = TypeVar("_T")
_UnpatchT = TypeVar("_UnpatchT", type, types.FunctionType)
import setuptools
__all__: list[str] = []
__all__ = []
"""
Everything is private. Contact the project team
if you think you need this functionality.
@@ -37,43 +33,52 @@ def _get_mro(cls):
return inspect.getmro(cls)
@overload
def get_unpatched(item: _UnpatchT) -> _UnpatchT: ...
@overload
def get_unpatched(item: object) -> None: ...
def get_unpatched(
item: type | types.FunctionType | object,
) -> type | types.FunctionType | None:
if isinstance(item, type):
return get_unpatched_class(item)
if isinstance(item, types.FunctionType):
return get_unpatched_function(item)
return None
def get_unpatched(item):
lookup = (
get_unpatched_class if isinstance(item, type) else
get_unpatched_function if isinstance(item, types.FunctionType) else
lambda item: None
)
return lookup(item)
def get_unpatched_class(cls: type[_T]) -> type[_T]:
def get_unpatched_class(cls):
"""Protect against re-patching the distutils if reloaded
Also ensures that no other distutils extension monkeypatched the distutils
first.
"""
external_bases = (
cast(type[_T], cls)
cls
for cls in _get_mro(cls)
if not cls.__module__.startswith('setuptools')
)
base = next(external_bases)
if not base.__module__.startswith('distutils'):
msg = f"distutils has already been patched by {cls!r}"
msg = "distutils has already been patched by %r" % cls
raise AssertionError(msg)
return base
def patch_all():
import setuptools
# we can't patch distutils.cmd, alas
distutils.core.Command = setuptools.Command # type: ignore[misc,assignment] # monkeypatching
distutils.core.Command = setuptools.Command
has_issue_12885 = sys.version_info <= (3, 5, 3)
if has_issue_12885:
# fix findall bug in distutils (http://bugs.python.org/issue12885)
distutils.filelist.findall = setuptools.findall
needs_warehouse = (
(3, 4) < sys.version_info < (3, 4, 6)
or
(3, 5) < sys.version_info <= (3, 5, 3)
)
if needs_warehouse:
warehouse = 'https://upload.pypi.org/legacy/'
distutils.config.PyPIRCCommand.DEFAULT_REPOSITORY = warehouse
_patch_distribution_metadata()
@@ -82,26 +87,20 @@ def patch_all():
module.Distribution = setuptools.dist.Distribution
# Install the patched Extension
distutils.core.Extension = setuptools.extension.Extension # type: ignore[misc,assignment] # monkeypatching
distutils.extension.Extension = setuptools.extension.Extension # type: ignore[misc,assignment] # monkeypatching
distutils.core.Extension = setuptools.extension.Extension
distutils.extension.Extension = setuptools.extension.Extension
if 'distutils.command.build_ext' in sys.modules:
sys.modules[
'distutils.command.build_ext'
].Extension = setuptools.extension.Extension
sys.modules['distutils.command.build_ext'].Extension = (
setuptools.extension.Extension
)
patch_for_msvc_specialized_compiler()
def _patch_distribution_metadata():
from . import _core_metadata
"""Patch write_pkg_file and read_pkg_file for higher metadata standards"""
for attr in (
'write_pkg_info',
'write_pkg_file',
'read_pkg_file',
'get_metadata_version',
'get_fullname',
):
new_val = getattr(_core_metadata, attr)
for attr in ('write_pkg_file', 'read_pkg_file', 'get_metadata_version'):
new_val = getattr(setuptools.dist, attr)
setattr(distutils.dist.DistributionMetadata, attr, new_val)
@@ -123,4 +122,44 @@ def patch_func(replacement, target_mod, func_name):
def get_unpatched_function(candidate):
return candidate.unpatched
return getattr(candidate, 'unpatched')
def patch_for_msvc_specialized_compiler():
"""
Patch functions in distutils to use standalone Microsoft Visual C++
compilers.
"""
# import late to avoid circular imports on Python < 3.5
msvc = import_module('setuptools.msvc')
if platform.system() != 'Windows':
# Compilers only available on Microsoft Windows
return
def patch_params(mod_name, func_name):
"""
Prepare the parameters for patch_func to patch indicated function.
"""
repl_prefix = 'msvc14_'
repl_name = repl_prefix + func_name.lstrip('_')
repl = getattr(msvc, repl_name)
mod = import_module(mod_name)
if not hasattr(mod, func_name):
raise ImportError(func_name)
return repl, mod, func_name
# Python 3.5+
msvc14 = functools.partial(patch_params, 'distutils._msvccompiler')
try:
# Patch distutils._msvccompiler._get_vc_env
patch_func(*msvc14('_get_vc_env'))
except ImportError:
pass
try:
# Patch distutils._msvccompiler.gen_lib_options for Numpy
patch_func(*msvc14('gen_lib_options'))
except ImportError:
pass