loosecanvas / tests /test_import_resolver.py
Joshua Sundance Bailey
loosecanvas: local AI thought-mapping canvas with a trust-tagged knowledge graph
6d1438c
Raw
History Blame Contribute Delete
4.98 kB
"""Red/green tests for M06 — Import Resolver (``resolve_imports``).
Assumed ``module_map`` shape (the real shape M04 ``walk_repo`` emits): a mapping of
``{relative_posix_path -> qualified_dotted_module_name}``, e.g.
``{"pkg/sub/mod_b.py": "pkg.sub.mod_b", "pkg/__init__.py": "pkg"}``.
Target/source node ids are reconstructed in the M05 module-node format
``{relative_path}::module::{last_dotted_segment}`` (M05 uses the file stem, or the package
name for ``__init__.py``, which is always the final segment of the dotted module name).
"""
from __future__ import annotations
from loosecanvas.contracts import Edge, RawImport
from loosecanvas.extractors.import_resolver import resolve_imports
# A small in-repo package tree: rel_path -> qualified dotted module name (M04 module_map).
MODULE_MAP: dict[str, str] = {
"pkg/__init__.py": "pkg",
"pkg/mod_a.py": "pkg.mod_a",
"pkg/sub/__init__.py": "pkg.sub",
"pkg/sub/mod_b.py": "pkg.sub.mod_b",
"pkg/sub/mod_c.py": "pkg.sub.mod_c",
}
# Module node ids as M05 would have minted them.
NODE_MOD_A = "pkg/mod_a.py::module::mod_a"
NODE_MOD_B = "pkg/sub/mod_b.py::module::mod_b"
NODE_MOD_C = "pkg/sub/mod_c.py::module::mod_c"
def _only(edges: list[Edge]) -> Edge:
assert len(edges) == 1, f"expected exactly one edge, got {edges}"
return edges[0]
def test_absolute_import_resolves_intra_repo() -> None:
"""``import pkg.mod_a`` from mod_b -> an ``imports`` edge between the two module nodes."""
raw = [
RawImport(
module="pkg.mod_a", names=[], level=0, current_file="pkg/sub/mod_b.py"
)
]
edge = _only(resolve_imports(raw, MODULE_MAP, "pkg/sub/mod_b.py"))
assert edge.kind == "imports"
assert edge.source == NODE_MOD_B
assert edge.target == NODE_MOD_A
def test_absolute_import_goes_external() -> None:
"""``import os`` -> an ``external_import`` edge to ``external::os``."""
raw = [RawImport(module="os", names=[], level=0, current_file="pkg/mod_a.py")]
edge = _only(resolve_imports(raw, MODULE_MAP, "pkg/mod_a.py"))
assert edge.kind == "external_import"
assert edge.target == "external::os"
def test_single_level_relative_resolves_sibling() -> None:
"""``from .mod_c import thing`` (level=1) in mod_b -> ``imports_from`` edge to mod_c."""
raw = [
RawImport(
module="mod_c", names=["thing"], level=1, current_file="pkg/sub/mod_b.py"
)
]
edge = _only(resolve_imports(raw, MODULE_MAP, "pkg/sub/mod_b.py"))
assert edge.kind == "imports_from"
assert edge.source == NODE_MOD_B
assert edge.target == NODE_MOD_C
def test_multi_level_relative_resolves_parent_package() -> None:
"""``from ..mod_a import x`` (level=2) in mod_b -> ``imports_from`` edge to mod_a."""
raw = [
RawImport(module="mod_a", names=["x"], level=2, current_file="pkg/sub/mod_b.py")
]
edge = _only(resolve_imports(raw, MODULE_MAP, "pkg/sub/mod_b.py"))
assert edge.kind == "imports_from"
assert edge.source == NODE_MOD_B
assert edge.target == NODE_MOD_A
def test_star_import_handled_without_error() -> None:
"""``from pkg.mod_a import *`` -> a single ``imports_from`` edge, no exception."""
raw = [
RawImport(
module="pkg.mod_a", names=["*"], level=0, current_file="pkg/sub/mod_b.py"
)
]
edge = _only(resolve_imports(raw, MODULE_MAP, "pkg/sub/mod_b.py"))
assert edge.kind == "imports_from"
assert edge.target == NODE_MOD_A
def test_unresolved_module_becomes_external_dep() -> None:
"""``from somelib.foo import bar`` -> ``external_import`` edge to ``external::somelib.foo``."""
raw = [
RawImport(
module="somelib.foo", names=["bar"], level=0, current_file="pkg/mod_a.py"
)
]
edge = _only(resolve_imports(raw, MODULE_MAP, "pkg/mod_a.py"))
assert edge.kind == "external_import"
assert edge.target == "external::somelib.foo"
def test_no_dangling_intra_repo_edge_endpoints() -> None:
"""Every endpoint of an intra-repo edge is a real module node id from ``module_map``."""
known_node_ids = {
f"{rel}::module::{dotted.rsplit('.', 1)[-1]}"
for rel, dotted in MODULE_MAP.items()
}
raw = [
RawImport(
module="pkg.mod_a", names=[], level=0, current_file="pkg/sub/mod_b.py"
),
RawImport(
module="mod_c", names=["thing"], level=1, current_file="pkg/sub/mod_b.py"
),
RawImport(
module="mod_a", names=["x"], level=2, current_file="pkg/sub/mod_b.py"
),
RawImport(module="os", names=[], level=0, current_file="pkg/sub/mod_b.py"),
]
edges = resolve_imports(raw, MODULE_MAP, "pkg/sub/mod_b.py")
for edge in edges:
if edge.kind == "external_import":
continue
assert edge.source in known_node_ids, f"dangling source: {edge.source}"
assert edge.target in known_node_ids, f"dangling target: {edge.target}"