Refactor is_importable and improve docs

This commit is contained in:
Bruno Oliveira 2024-04-06 18:41:40 -03:00
parent 04cbe4f640
commit b6c0190f15
2 changed files with 19 additions and 10 deletions

View File

@ -788,7 +788,8 @@ def resolve_pkg_root_and_module_name(
if consider_namespace_packages: if consider_namespace_packages:
start = pkg_root if pkg_root is not None else path.parent start = pkg_root if pkg_root is not None else path.parent
for candidate in (start, *start.parents): for candidate in (start, *start.parents):
if is_importable(candidate, path): module_name = compute_module_name(candidate, path)
if is_importable(module_name, path):
# Point the pkg_root to the root of the namespace package. # Point the pkg_root to the root of the namespace package.
pkg_root = candidate pkg_root = candidate
break break
@ -800,17 +801,25 @@ def resolve_pkg_root_and_module_name(
raise CouldNotResolvePathError(f"Could not resolve for {path}") raise CouldNotResolvePathError(f"Could not resolve for {path}")
def is_importable(root: Path, module_path: Path) -> bool: def is_importable(module_name: str, module_path: Path) -> bool:
""" """
Return if the given module path could be imported normally by Python, akin to the user Return if the given module path could be imported normally by Python, akin to the user
entering the REPL and importing the corresponding module name directly. entering the REPL and importing the corresponding module name directly, and corresponds
to the module_path specified.
:param module_name:
Full module name that we want to check if is importable.
For example, "app.models".
:param module_path:
Full path to the python module/package we want to check if is importable.
For example, "/projects/src/app/models.py".
""" """
module_name = compute_module_name(root, module_path)
try: try:
# Note this is different from what we do in ``import_path``, where we also search sys.meta_path. # Note this is different from what we do in ``_import_module_using_spec``, where we explicitly search through
# Searching sys.meta_path will eventually find a spec which can load the file even if the interpreter would # sys.meta_path to be able to pass the path of the module that we want to import (``meta_importer.find_spec``).
# not find this module normally in the REPL, which is exactly what we want to be able to do in # Using importlib.util.find_spec() is different, it gives the same results as trying to import
# ``import_path``, but not here. # the module normally in the REPL.
spec = importlib.util.find_spec(module_name) spec = importlib.util.find_spec(module_name)
except (ImportError, ValueError, ImportWarning): except (ImportError, ValueError, ImportWarning):
return False return False

View File

@ -1377,11 +1377,11 @@ def test_is_importable_bad_arguments(pytester: Pytester) -> None:
pytester.syspathinsert() pytester.syspathinsert()
path = pytester.path / "bar.x" path = pytester.path / "bar.x"
path.mkdir() path.mkdir()
assert is_importable(path.parent, path) is False assert is_importable("bar.x", path) is False
path = pytester.path / ".bar.x" path = pytester.path / ".bar.x"
path.mkdir() path.mkdir()
assert is_importable(path.parent, path) is False assert is_importable(".bar.x", path) is False
def test_compute_module_name(tmp_path: Path) -> None: def test_compute_module_name(tmp_path: Path) -> None: