@@ -133,36 +133,66 @@ def find_module(
133
133
processed : list [str ],
134
134
submodule_path : Sequence [str ] | None ,
135
135
) -> ModuleSpec | None :
136
- if submodule_path is not None :
137
- submodule_path = list ( submodule_path )
138
- elif modname in sys .builtin_module_names :
136
+ # Although we should be able to use `find_spec` this doesn't work on PyPy for builtins.
137
+ # Therefore, we use the `builtin_module_nams` heuristic for these.
138
+ if submodule_path is None and modname in sys .builtin_module_names :
139
139
return ModuleSpec (
140
140
name = modname ,
141
141
location = None ,
142
142
type = ModuleType .C_BUILTIN ,
143
143
)
144
- else :
145
- try :
146
- with warnings .catch_warnings ():
147
- warnings .filterwarnings ("ignore" , category = UserWarning )
148
- spec = importlib .util .find_spec (modname )
144
+
145
+ # sys.stdlib_module_names was added in Python 3.10
146
+ if PY310_PLUS :
147
+ # If the module is a stdlib module, check whether this is a frozen module. Note that
148
+ # `find_spec` actually imports the module, so we want to make sure we only run this code
149
+ # for stuff that can be expected to be frozen. For now this is only stdlib.
150
+ if modname in sys .stdlib_module_names or (
151
+ processed and processed [0 ] in sys .stdlib_module_names
152
+ ):
153
+ spec = importlib .util .find_spec ("." .join ((* processed , modname )))
149
154
if (
150
155
spec
151
156
and spec .loader # type: ignore[comparison-overlap] # noqa: E501
152
157
is importlib .machinery .FrozenImporter
153
158
):
154
- # No need for BuiltinImporter; builtins handled above
155
159
return ModuleSpec (
156
160
name = modname ,
157
161
location = getattr (spec .loader_state , "filename" , None ),
158
162
type = ModuleType .PY_FROZEN ,
159
163
)
160
- except ValueError :
161
- pass
162
- submodule_path = sys .path
164
+ else :
165
+ # NOTE: This is broken code. It doesn't work on Python 3.13+ where submodules can also
166
+ # be frozen. However, we don't want to worry about this and we don't want to break
167
+ # support for older versions of Python. This is just copy-pasted from the old non
168
+ # working version to at least have no functional behaviour change on <=3.10.
169
+ # It can be removed after 3.10 is no longer supported in favour of the logic above.
170
+ if submodule_path is None : # pylint: disable=else-if-used
171
+ try :
172
+ with warnings .catch_warnings ():
173
+ warnings .filterwarnings ("ignore" , category = UserWarning )
174
+ spec = importlib .util .find_spec (modname )
175
+ if (
176
+ spec
177
+ and spec .loader # type: ignore[comparison-overlap] # noqa: E501
178
+ is importlib .machinery .FrozenImporter
179
+ ):
180
+ # No need for BuiltinImporter; builtins handled above
181
+ return ModuleSpec (
182
+ name = modname ,
183
+ location = getattr (spec .loader_state , "filename" , None ),
184
+ type = ModuleType .PY_FROZEN ,
185
+ )
186
+ except ValueError :
187
+ pass
188
+
189
+ if submodule_path is not None :
190
+ search_paths = list (submodule_path )
191
+ else :
192
+ search_paths = sys .path
163
193
164
194
suffixes = (".py" , ".pyi" , importlib .machinery .BYTECODE_SUFFIXES [0 ])
165
- for entry in submodule_path :
195
+ for entry in search_paths :
166
196
package_directory = os .path .join (entry , modname )
167
197
for suffix in suffixes :
168
198
package_file_name = "__init__" + suffix
@@ -231,13 +261,12 @@ def find_module(
231
261
if processed :
232
262
modname = "." .join ([* processed , modname ])
233
263
if util .is_namespace (modname ) and modname in sys .modules :
234
- submodule_path = sys .modules [modname ].__path__
235
264
return ModuleSpec (
236
265
name = modname ,
237
266
location = "" ,
238
267
origin = "namespace" ,
239
268
type = ModuleType .PY_NAMESPACE ,
240
- submodule_search_locations = submodule_path ,
269
+ submodule_search_locations = sys . modules [ modname ]. __path__ ,
241
270
)
242
271
return None
243
272
@@ -353,13 +382,15 @@ def _search_zip(
353
382
if PY310_PLUS :
354
383
if not importer .find_spec (os .path .sep .join (modpath )):
355
384
raise ImportError (
356
- "No module named %s in %s/%s"
357
- % ("." .join (modpath [1 :]), filepath , modpath )
385
+ "No module named {} in {}/{}" .format (
386
+ "." .join (modpath [1 :]), filepath , modpath
387
+ )
358
388
)
359
389
elif not importer .find_module (os .path .sep .join (modpath )):
360
390
raise ImportError (
361
- "No module named %s in %s/%s"
362
- % ("." .join (modpath [1 :]), filepath , modpath )
391
+ "No module named {} in {}/{}" .format (
392
+ "." .join (modpath [1 :]), filepath , modpath
393
+ )
363
394
)
364
395
return (
365
396
ModuleType .PY_ZIPMODULE ,
0 commit comments