@@ -14,22 +14,26 @@ def warn_distutils_present():
14
14
# https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
15
15
return
16
16
import warnings
17
+
17
18
warnings .warn (
18
19
"Distutils was imported before Setuptools, but importing Setuptools "
19
20
"also replaces the `distutils` module in `sys.modules`. This may lead "
20
21
"to undesirable behaviors or errors. To avoid these issues, avoid "
21
22
"using distutils directly, ensure that setuptools is installed in the "
22
23
"traditional way (e.g. not an editable install), and/or make sure "
23
- "that setuptools is always imported before distutils." )
24
+ "that setuptools is always imported before distutils."
25
+ )
24
26
25
27
26
28
def clear_distutils ():
27
29
if 'distutils' not in sys .modules :
28
30
return
29
31
import warnings
32
+
30
33
warnings .warn ("Setuptools is replacing distutils." )
31
34
mods = [
32
- name for name in sys .modules
35
+ name
36
+ for name in sys .modules
33
37
if name == "distutils" or name .startswith ("distutils." )
34
38
]
35
39
for name in mods :
@@ -46,6 +50,7 @@ def enabled():
46
50
47
51
def ensure_local_distutils ():
48
52
import importlib
53
+
49
54
clear_distutils ()
50
55
51
56
# With the DistutilsMetaFinder in place,
@@ -82,7 +87,9 @@ def match(self, string):
82
87
83
88
class DistutilsMetaFinder :
84
89
def find_spec (self , fullname , path , target = None ):
85
- if path is not None :
90
+ # optimization: only consider top level modules and those
91
+ # found in the CPython test suite.
92
+ if path is not None and not fullname .startswith ('test.' ):
86
93
return
87
94
88
95
method_name = 'spec_for_{fullname}' .format (** locals ())
@@ -111,7 +118,6 @@ def spec_for_distutils(self):
111
118
return
112
119
113
120
class DistutilsLoader (importlib .abc .Loader ):
114
-
115
121
def create_module (self , spec ):
116
122
mod .__name__ = 'distutils'
117
123
return mod
@@ -147,9 +153,9 @@ def pip_imported_during_build(cls):
147
153
Detect if pip is being imported in a build script. Ref #2355.
148
154
"""
149
155
import traceback
156
+
150
157
return any (
151
- cls .frame_file_is_setup (frame )
152
- for frame , line in traceback .walk_stack (None )
158
+ cls .frame_file_is_setup (frame ) for frame , line in traceback .walk_stack (None )
153
159
)
154
160
155
161
@staticmethod
@@ -160,6 +166,35 @@ def frame_file_is_setup(frame):
160
166
# some frames may not have __file__ (#2940)
161
167
return frame .f_globals .get ('__file__' , '' ).endswith ('setup.py' )
162
168
169
+ def spec_for_sensitive_tests (self ):
170
+ """
171
+ Ensure stdlib distutils when running select tests under CPython.
172
+
173
+ python/cpython#91169
174
+ """
175
+ clear_distutils ()
176
+ self .spec_for_distutils = lambda : None
177
+
178
+ sensitive_tests = (
179
+ [
180
+ 'test.test_distutils' ,
181
+ 'test.test_peg_generator' ,
182
+ 'test.test_importlib' ,
183
+ ]
184
+ if sys .version_info < (3 , 10 )
185
+ else [
186
+ 'test.test_distutils' ,
187
+ ]
188
+ )
189
+
190
+
191
+ for name in DistutilsMetaFinder .sensitive_tests :
192
+ setattr (
193
+ DistutilsMetaFinder ,
194
+ f'spec_for_{ name } ' ,
195
+ DistutilsMetaFinder .spec_for_sensitive_tests ,
196
+ )
197
+
163
198
164
199
DISTUTILS_FINDER = DistutilsMetaFinder ()
165
200
0 commit comments