comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/setuptools/monkey.py @ 68:5028fdace37b

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