Skip to content

Deps

deps

Source-module dependency gathering (imports + module-level constants).

gather_source_constants(tree)

Map module-level constant names to their SimpleStatementLine.

Source code in packages/axm-anvil/src/axm_anvil/core/deps.py
Python
def gather_source_constants(
    tree: cst.Module,
) -> dict[str, cst.SimpleStatementLine]:
    """Map module-level constant names to their ``SimpleStatementLine``."""
    mapping: dict[str, cst.SimpleStatementLine] = {}
    for stmt in tree.body:
        if not isinstance(stmt, cst.SimpleStatementLine):
            continue
        for inner in stmt.body:
            if isinstance(inner, cst.Assign):
                if len(inner.targets) == 1 and isinstance(
                    inner.targets[0].target, cst.Name
                ):
                    mapping[inner.targets[0].target.value] = stmt
            elif isinstance(inner, cst.AnnAssign) and isinstance(
                inner.target, cst.Name
            ):
                mapping[inner.target.value] = stmt
    return mapping

gather_source_helpers(tree)

Map top-level FunctionDef / ClassDef names to their node.

Source code in packages/axm-anvil/src/axm_anvil/core/deps.py
Python
def gather_source_helpers(
    tree: cst.Module,
) -> dict[str, cst.FunctionDef | cst.ClassDef]:
    """Map top-level ``FunctionDef`` / ``ClassDef`` names to their node."""
    mapping: dict[str, cst.FunctionDef | cst.ClassDef] = {}
    for stmt in tree.body:
        if isinstance(stmt, cst.FunctionDef | cst.ClassDef):
            mapping[stmt.name.value] = stmt
    return mapping

gather_source_imports(tree)

Map local names to the ImportInfo describing their origin.

Imports nested in a top-level try/except or if guard are flagged conditional=True with a handle on the guarding block.

Source code in packages/axm-anvil/src/axm_anvil/core/deps.py
Python
def gather_source_imports(tree: cst.Module) -> dict[str, ImportInfo]:
    """Map local names to the ``ImportInfo`` describing their origin.

    Imports nested in a top-level ``try``/``except`` or ``if`` guard are
    flagged ``conditional=True`` with a handle on the guarding block.
    """
    return _gather_imports(tree)

topo_sort_constants(constants)

Topologically sort constants so deps appear before dependents.

Cycles are tolerated — back-edges are skipped and all members are still emitted (Python would raise NameError at runtime for a genuine cycle, so arbitrary order among cycle members is acceptable).

Source code in packages/axm-anvil/src/axm_anvil/core/deps.py
Python
def topo_sort_constants(
    constants: dict[str, cst.SimpleStatementLine],
) -> list[cst.SimpleStatementLine]:
    """Topologically sort constants so deps appear before dependents.

    Cycles are tolerated — back-edges are skipped and all members are
    still emitted (Python would raise ``NameError`` at runtime for a
    genuine cycle, so arbitrary order among cycle members is acceptable).
    """
    keys = set(constants)
    deps: dict[str, set[str]] = {}
    for name, stmt in constants.items():
        collector = ReferenceCollector()
        stmt.visit(collector)
        deps[name] = (collector.names & keys) - {name}

    ordered: list[str] = []
    visited: set[str] = set()
    in_stack: set[str] = set()

    def visit(node: str) -> None:
        """DFS post-order helper that emits constants in dependency order."""
        if node in visited or node in in_stack:
            return
        in_stack.add(node)
        for dep in deps[node]:
            visit(dep)
        in_stack.discard(node)
        visited.add(node)
        ordered.append(node)

    for name in constants:
        visit(name)

    return [constants[n] for n in ordered]