annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/setuptools/monkey.py @ 69:33d812a61356

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
rev   line source
jpayne@69 1 """
jpayne@69 2 Monkey patching of distutils.
jpayne@69 3 """
jpayne@69 4
jpayne@69 5 from __future__ import annotations
jpayne@69 6
jpayne@69 7 import inspect
jpayne@69 8 import platform
jpayne@69 9 import sys
jpayne@69 10 import types
jpayne@69 11 from typing import Type, TypeVar, cast, overload
jpayne@69 12
jpayne@69 13 import distutils.filelist
jpayne@69 14
jpayne@69 15 _T = TypeVar("_T")
jpayne@69 16 _UnpatchT = TypeVar("_UnpatchT", type, types.FunctionType)
jpayne@69 17
jpayne@69 18
jpayne@69 19 __all__: list[str] = []
jpayne@69 20 """
jpayne@69 21 Everything is private. Contact the project team
jpayne@69 22 if you think you need this functionality.
jpayne@69 23 """
jpayne@69 24
jpayne@69 25
jpayne@69 26 def _get_mro(cls):
jpayne@69 27 """
jpayne@69 28 Returns the bases classes for cls sorted by the MRO.
jpayne@69 29
jpayne@69 30 Works around an issue on Jython where inspect.getmro will not return all
jpayne@69 31 base classes if multiple classes share the same name. Instead, this
jpayne@69 32 function will return a tuple containing the class itself, and the contents
jpayne@69 33 of cls.__bases__. See https://github.com/pypa/setuptools/issues/1024.
jpayne@69 34 """
jpayne@69 35 if platform.python_implementation() == "Jython":
jpayne@69 36 return (cls,) + cls.__bases__
jpayne@69 37 return inspect.getmro(cls)
jpayne@69 38
jpayne@69 39
jpayne@69 40 @overload
jpayne@69 41 def get_unpatched(item: _UnpatchT) -> _UnpatchT: ...
jpayne@69 42 @overload
jpayne@69 43 def get_unpatched(item: object) -> None: ...
jpayne@69 44 def get_unpatched(
jpayne@69 45 item: type | types.FunctionType | object,
jpayne@69 46 ) -> type | types.FunctionType | None:
jpayne@69 47 if isinstance(item, type):
jpayne@69 48 return get_unpatched_class(item)
jpayne@69 49 if isinstance(item, types.FunctionType):
jpayne@69 50 return get_unpatched_function(item)
jpayne@69 51 return None
jpayne@69 52
jpayne@69 53
jpayne@69 54 def get_unpatched_class(cls: type[_T]) -> type[_T]:
jpayne@69 55 """Protect against re-patching the distutils if reloaded
jpayne@69 56
jpayne@69 57 Also ensures that no other distutils extension monkeypatched the distutils
jpayne@69 58 first.
jpayne@69 59 """
jpayne@69 60 external_bases = (
jpayne@69 61 cast(Type[_T], cls)
jpayne@69 62 for cls in _get_mro(cls)
jpayne@69 63 if not cls.__module__.startswith('setuptools')
jpayne@69 64 )
jpayne@69 65 base = next(external_bases)
jpayne@69 66 if not base.__module__.startswith('distutils'):
jpayne@69 67 msg = "distutils has already been patched by %r" % cls
jpayne@69 68 raise AssertionError(msg)
jpayne@69 69 return base
jpayne@69 70
jpayne@69 71
jpayne@69 72 def patch_all():
jpayne@69 73 import setuptools
jpayne@69 74
jpayne@69 75 # we can't patch distutils.cmd, alas
jpayne@69 76 distutils.core.Command = setuptools.Command
jpayne@69 77
jpayne@69 78 _patch_distribution_metadata()
jpayne@69 79
jpayne@69 80 # Install Distribution throughout the distutils
jpayne@69 81 for module in distutils.dist, distutils.core, distutils.cmd:
jpayne@69 82 module.Distribution = setuptools.dist.Distribution
jpayne@69 83
jpayne@69 84 # Install the patched Extension
jpayne@69 85 distutils.core.Extension = setuptools.extension.Extension
jpayne@69 86 distutils.extension.Extension = setuptools.extension.Extension
jpayne@69 87 if 'distutils.command.build_ext' in sys.modules:
jpayne@69 88 sys.modules[
jpayne@69 89 'distutils.command.build_ext'
jpayne@69 90 ].Extension = setuptools.extension.Extension
jpayne@69 91
jpayne@69 92
jpayne@69 93 def _patch_distribution_metadata():
jpayne@69 94 from . import _core_metadata
jpayne@69 95
jpayne@69 96 """Patch write_pkg_file and read_pkg_file for higher metadata standards"""
jpayne@69 97 for attr in (
jpayne@69 98 'write_pkg_info',
jpayne@69 99 'write_pkg_file',
jpayne@69 100 'read_pkg_file',
jpayne@69 101 'get_metadata_version',
jpayne@69 102 'get_fullname',
jpayne@69 103 ):
jpayne@69 104 new_val = getattr(_core_metadata, attr)
jpayne@69 105 setattr(distutils.dist.DistributionMetadata, attr, new_val)
jpayne@69 106
jpayne@69 107
jpayne@69 108 def patch_func(replacement, target_mod, func_name):
jpayne@69 109 """
jpayne@69 110 Patch func_name in target_mod with replacement
jpayne@69 111
jpayne@69 112 Important - original must be resolved by name to avoid
jpayne@69 113 patching an already patched function.
jpayne@69 114 """
jpayne@69 115 original = getattr(target_mod, func_name)
jpayne@69 116
jpayne@69 117 # set the 'unpatched' attribute on the replacement to
jpayne@69 118 # point to the original.
jpayne@69 119 vars(replacement).setdefault('unpatched', original)
jpayne@69 120
jpayne@69 121 # replace the function in the original module
jpayne@69 122 setattr(target_mod, func_name, replacement)
jpayne@69 123
jpayne@69 124
jpayne@69 125 def get_unpatched_function(candidate):
jpayne@69 126 return candidate.unpatched