Skip to content

Commit a8439ff

Browse files
authored
Cache find_module calls (#2543)
1 parent 9371982 commit a8439ff

File tree

2 files changed

+25
-13
lines changed

2 files changed

+25
-13
lines changed

astroid/interpreter/_import/spec.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def find_module(
9292
modname: str,
9393
module_parts: tuple[str, ...],
9494
processed: tuple[str, ...],
95-
submodule_path: Sequence[str] | None,
95+
submodule_path: tuple[str, ...] | None,
9696
) -> ModuleSpec | None:
9797
"""Find the given module.
9898
@@ -105,7 +105,7 @@ def find_module(
105105
namespace.
106106
:param processed: What parts from the module parts were processed
107107
so far.
108-
:param submodule_path: A list of paths where the module
108+
:param submodule_path: A tuple of paths where the module
109109
can be looked into.
110110
:returns: A ModuleSpec, describing how and where the module was found,
111111
None, otherwise.
@@ -127,11 +127,12 @@ class ImportlibFinder(Finder):
127127
)
128128

129129
@staticmethod
130+
@lru_cache(maxsize=1024)
130131
def find_module(
131132
modname: str,
132133
module_parts: tuple[str, ...],
133134
processed: tuple[str, ...],
134-
submodule_path: Sequence[str] | None,
135+
submodule_path: tuple[str, ...] | None,
135136
) -> ModuleSpec | None:
136137
if submodule_path is not None:
137138
search_paths = list(submodule_path)
@@ -222,11 +223,12 @@ class ExplicitNamespacePackageFinder(ImportlibFinder):
222223
"""A finder for the explicit namespace packages."""
223224

224225
@staticmethod
226+
@lru_cache(maxsize=1024)
225227
def find_module(
226228
modname: str,
227229
module_parts: tuple[str, ...],
228230
processed: tuple[str, ...],
229-
submodule_path: Sequence[str] | None,
231+
submodule_path: tuple[str, ...] | None,
230232
) -> ModuleSpec | None:
231233
if processed:
232234
modname = ".".join([*processed, modname])
@@ -261,11 +263,12 @@ def __init__(self, path: Sequence[str]) -> None:
261263
continue
262264

263265
@staticmethod
266+
@lru_cache(maxsize=1024)
264267
def find_module(
265268
modname: str,
266269
module_parts: tuple[str, ...],
267270
processed: tuple[str, ...],
268-
submodule_path: Sequence[str] | None,
271+
submodule_path: tuple[str, ...] | None,
269272
) -> ModuleSpec | None:
270273
try:
271274
file_type, filename, path = _search_zip(module_parts)
@@ -285,11 +288,12 @@ class PathSpecFinder(Finder):
285288
"""Finder based on importlib.machinery.PathFinder."""
286289

287290
@staticmethod
291+
@lru_cache(maxsize=1024)
288292
def find_module(
289293
modname: str,
290294
module_parts: tuple[str, ...],
291295
processed: tuple[str, ...],
292-
submodule_path: Sequence[str] | None,
296+
submodule_path: tuple[str, ...] | None,
293297
) -> ModuleSpec | None:
294298
spec = importlib.machinery.PathFinder.find_spec(modname, path=submodule_path)
295299
if spec is not None:
@@ -373,7 +377,7 @@ def _find_spec_with_path(
373377
modname: str,
374378
module_parts: tuple[str, ...],
375379
processed: tuple[str, ...],
376-
submodule_path: Sequence[str] | None,
380+
submodule_path: tuple[str, ...] | None,
377381
) -> tuple[Finder | _MetaPathFinder, ModuleSpec]:
378382
for finder in _SPEC_FINDERS:
379383
finder_instance = finder(search_path)
@@ -451,25 +455,30 @@ def _find_spec(
451455
# Need a copy for not mutating the argument.
452456
modpath = list(module_path)
453457

454-
submodule_path = None
458+
search_paths = None
455459
processed: list[str] = []
456460

457461
while modpath:
458462
modname = modpath.pop(0)
463+
464+
submodule_path = search_paths or path
465+
if submodule_path is not None:
466+
submodule_path = tuple(submodule_path)
467+
459468
finder, spec = _find_spec_with_path(
460-
_path, modname, module_path, tuple(processed), submodule_path or path
469+
_path, modname, module_path, tuple(processed), submodule_path
461470
)
462471
processed.append(modname)
463472
if modpath:
464473
if isinstance(finder, Finder):
465-
submodule_path = finder.contribute_to_path(spec, processed)
466-
# If modname is a package from an editable install, update submodule_path
474+
search_paths = finder.contribute_to_path(spec, processed)
475+
# If modname is a package from an editable install, update search_paths
467476
# so that the next module in the path will be found inside of it using importlib.
468477
# Existence of __name__ is guaranteed by _find_spec_with_path.
469478
elif finder.__name__ in _EditableFinderClasses: # type: ignore[attr-defined]
470-
submodule_path = spec.submodule_search_locations
479+
search_paths = spec.submodule_search_locations
471480

472481
if spec.type == ModuleType.PKG_DIRECTORY:
473-
spec = spec._replace(submodule_search_locations=submodule_path)
482+
spec = spec._replace(submodule_search_locations=search_paths)
474483

475484
return spec

astroid/manager.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,9 @@ def clear_cache(self) -> None:
482482
):
483483
lru_cache.cache_clear() # type: ignore[attr-defined]
484484

485+
for finder in spec._SPEC_FINDERS:
486+
finder.find_module.cache_clear()
487+
485488
self.bootstrap()
486489

487490
# Reload brain plugins. During initialisation this is done in astroid.manager.py

0 commit comments

Comments
 (0)