Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache find_module calls #2543

Merged
merged 2 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 22 additions & 13 deletions astroid/interpreter/_import/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def find_module(
modname: str,
module_parts: tuple[str, ...],
processed: tuple[str, ...],
submodule_path: Sequence[str] | None,
submodule_path: tuple[str, ...] | None,
) -> ModuleSpec | None:
"""Find the given module.

Expand All @@ -105,7 +105,7 @@ def find_module(
namespace.
:param processed: What parts from the module parts were processed
so far.
:param submodule_path: A list of paths where the module
:param submodule_path: A tuple of paths where the module
can be looked into.
:returns: A ModuleSpec, describing how and where the module was found,
None, otherwise.
Expand All @@ -127,11 +127,12 @@ class ImportlibFinder(Finder):
)

@staticmethod
@lru_cache(maxsize=1024)
def find_module(
modname: str,
module_parts: tuple[str, ...],
processed: tuple[str, ...],
submodule_path: Sequence[str] | None,
submodule_path: tuple[str, ...] | None,
) -> ModuleSpec | None:
if submodule_path is not None:
search_paths = list(submodule_path)
Expand Down Expand Up @@ -222,11 +223,12 @@ class ExplicitNamespacePackageFinder(ImportlibFinder):
"""A finder for the explicit namespace packages."""

@staticmethod
@lru_cache(maxsize=1024)
def find_module(
modname: str,
module_parts: tuple[str, ...],
processed: tuple[str, ...],
submodule_path: Sequence[str] | None,
submodule_path: tuple[str, ...] | None,
) -> ModuleSpec | None:
if processed:
modname = ".".join([*processed, modname])
Expand Down Expand Up @@ -261,11 +263,12 @@ def __init__(self, path: Sequence[str]) -> None:
continue

@staticmethod
@lru_cache(maxsize=1024)
def find_module(
modname: str,
module_parts: tuple[str, ...],
processed: tuple[str, ...],
submodule_path: Sequence[str] | None,
submodule_path: tuple[str, ...] | None,
) -> ModuleSpec | None:
try:
file_type, filename, path = _search_zip(module_parts)
Expand All @@ -285,11 +288,12 @@ class PathSpecFinder(Finder):
"""Finder based on importlib.machinery.PathFinder."""

@staticmethod
@lru_cache(maxsize=1024)
def find_module(
modname: str,
module_parts: tuple[str, ...],
processed: tuple[str, ...],
submodule_path: Sequence[str] | None,
submodule_path: tuple[str, ...] | None,
) -> ModuleSpec | None:
spec = importlib.machinery.PathFinder.find_spec(modname, path=submodule_path)
if spec is not None:
Expand Down Expand Up @@ -373,7 +377,7 @@ def _find_spec_with_path(
modname: str,
module_parts: tuple[str, ...],
processed: tuple[str, ...],
submodule_path: Sequence[str] | None,
submodule_path: tuple[str, ...] | None,
) -> tuple[Finder | _MetaPathFinder, ModuleSpec]:
for finder in _SPEC_FINDERS:
finder_instance = finder(search_path)
Expand Down Expand Up @@ -451,25 +455,30 @@ def _find_spec(
# Need a copy for not mutating the argument.
modpath = list(module_path)

submodule_path = None
search_paths = None
processed: list[str] = []

while modpath:
modname = modpath.pop(0)

submodule_path = search_paths or path
if submodule_path is not None:
submodule_path = tuple(submodule_path)
jacobtylerwalls marked this conversation as resolved.
Show resolved Hide resolved

finder, spec = _find_spec_with_path(
_path, modname, module_path, tuple(processed), submodule_path or path
_path, modname, module_path, tuple(processed), submodule_path
)
processed.append(modname)
if modpath:
if isinstance(finder, Finder):
submodule_path = finder.contribute_to_path(spec, processed)
# If modname is a package from an editable install, update submodule_path
search_paths = finder.contribute_to_path(spec, processed)
# If modname is a package from an editable install, update search_paths
# so that the next module in the path will be found inside of it using importlib.
# Existence of __name__ is guaranteed by _find_spec_with_path.
elif finder.__name__ in _EditableFinderClasses: # type: ignore[attr-defined]
submodule_path = spec.submodule_search_locations
search_paths = spec.submodule_search_locations
jacobtylerwalls marked this conversation as resolved.
Show resolved Hide resolved

if spec.type == ModuleType.PKG_DIRECTORY:
spec = spec._replace(submodule_search_locations=submodule_path)
spec = spec._replace(submodule_search_locations=search_paths)

return spec
3 changes: 3 additions & 0 deletions astroid/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,9 @@ def clear_cache(self) -> None:
):
lru_cache.cache_clear() # type: ignore[attr-defined]

for finder in spec._SPEC_FINDERS:
finder.find_module.cache_clear()

self.bootstrap()

# Reload brain plugins. During initialisation this is done in astroid.manager.py
Expand Down
Loading