Skip to content

Inspect resolve

inspect_resolve

Symbol resolution helpers for InspectTool.

find_module_for_symbol(pkg, symbol)

Find the module containing a symbol.

Supports two lookup modes:

  • Object (FunctionInfo / ClassInfo): identity-first match, then name fallback.
  • String: name-based search across functions, methods, and classes.

Parameters:

Name Type Description Default
pkg PackageInfo

Analyzed package info.

required
symbol str | FunctionInfo | ClassInfo | VariableInfo

Symbol name or object to locate.

required

Returns:

Type Description
ModuleInfo | None

The ModuleInfo containing the symbol, or None.

Source code in packages/axm-ast/src/axm_ast/core/analyzer.py
Python
def find_module_for_symbol(
    pkg: PackageInfo,
    symbol: str | FunctionInfo | ClassInfo | VariableInfo,
) -> ModuleInfo | None:
    """Find the module containing a symbol.

    Supports two lookup modes:

    - **Object** (``FunctionInfo`` / ``ClassInfo``): identity-first match,
      then name fallback.
    - **String**: name-based search across functions, methods, and classes.

    Args:
        pkg: Analyzed package info.
        symbol: Symbol name or object to locate.

    Returns:
        The ``ModuleInfo`` containing the symbol, or ``None``.
    """
    if not isinstance(symbol, str):
        # Identity match (when passed an object)
        result = _find_module_by_identity(pkg, symbol)
        if result is not None:
            return result
        # Fallback to name-based search
        symbol = symbol.name

    return _find_module_by_name(pkg, symbol)

find_symbol_abs_path(pkg, sym)

Find the absolute file path for a symbol within the package.

Source code in packages/axm-ast/src/axm_ast/tools/inspect_resolve.py
Python
def find_symbol_abs_path(
    pkg: PackageInfo, sym: FunctionInfo | ClassInfo | VariableInfo
) -> str:
    """Find the absolute file path for a symbol within the package."""
    mod = find_module_for_symbol(pkg, sym)
    if mod is not None:
        return str(mod.path)
    return ""

find_symbol_file(pkg, sym)

Find the relative file path for a symbol within the package.

Source code in packages/axm-ast/src/axm_ast/tools/inspect_resolve.py
Python
def find_symbol_file(
    pkg: PackageInfo, sym: FunctionInfo | ClassInfo | VariableInfo
) -> str:
    """Find the relative file path for a symbol within the package."""
    mod = find_module_for_symbol(pkg, sym)
    if mod is not None:
        return relative_path(pkg, mod.path)
    return ""

inspect_dotted(pkg, symbol, *, source=False)

Resolve a dotted symbol (module, module.symbol, or Class.method).

Source code in packages/axm-ast/src/axm_ast/tools/inspect_resolve.py
Python
def inspect_dotted(
    pkg: PackageInfo, symbol: str, *, source: bool = False
) -> ToolResult:
    """Resolve a dotted symbol (module, module.symbol, or Class.method)."""
    result = inspect_module(pkg, symbol)
    if result is not None:
        return result

    result = resolve_module_symbol(pkg, symbol, source=source)
    if result is not None:
        return result

    result = resolve_class_method(pkg, symbol, source=source)
    if result is not None:
        return result

    return ToolResult(
        success=False,
        error=(
            f"Symbol '{symbol}' not found"
            " (tried module name, module.symbol, and Class.method)"
        ),
    )

inspect_module(pkg, name)

Try to resolve name as a module name and return module metadata.

Source code in packages/axm-ast/src/axm_ast/tools/inspect_resolve.py
Python
def inspect_module(pkg: PackageInfo, name: str) -> ToolResult | None:
    """Try to resolve *name* as a module name and return module metadata."""
    mod = resolve_module(pkg, name)
    if mod is None or isinstance(mod, ToolResult):
        return mod

    detail = build_module_detail(pkg, mod, name)
    return ToolResult(success=True, data={"symbol": detail})

resolve_class_method(pkg, dotted, *, source=False)

Try to resolve dotted as ClassName.method_name.

Returns None if no class matches.

Source code in packages/axm-ast/src/axm_ast/tools/inspect_resolve.py
Python
def resolve_class_method(
    pkg: PackageInfo, dotted: str, *, source: bool = False
) -> ToolResult | None:
    """Try to resolve ``dotted`` as ``ClassName.method_name``.

    Returns None if no class matches.
    """
    parts = dotted.split(".")
    class_name = parts[0]
    method_name = parts[-1]

    classes = search_symbols(
        pkg, name=class_name, returns=None, kind=None, inherits=None
    )
    cls = next(
        (c for c in classes if isinstance(c, ClassInfo) and c.name == class_name),
        None,
    )
    if cls is None:
        return None

    method = next((m for m in cls.methods if m.name == method_name), None)
    if method is None:
        return ToolResult(
            success=False,
            error=(f"Method '{method_name}' not found in class '{class_name}'"),
        )

    file_path = find_symbol_file(pkg, cls)
    abs_path = find_symbol_abs_path(pkg, cls)
    return ToolResult(
        success=True,
        data={
            "symbol": build_detail(
                method,
                file=file_path,
                abs_path=abs_path,
                source=source,
            )
        },
    )

resolve_module(pkg, name)

Resolve a name to a module via exact or substring match.

Source code in packages/axm-ast/src/axm_ast/tools/inspect_resolve.py
Python
def resolve_module(
    pkg: PackageInfo,
    name: str,
) -> ModuleInfo | ToolResult | None:
    """Resolve a name to a module via exact or substring match."""
    mod_names = pkg.module_names
    name_to_mod: dict[str, ModuleInfo] = dict(zip(mod_names, pkg.modules, strict=True))

    mod = name_to_mod.get(name)
    if mod is not None:
        return mod

    matches = [n for n in mod_names if name in n]
    if len(matches) == 1:
        return name_to_mod[matches[0]]
    if len(matches) > 1:
        return ToolResult(
            success=False,
            error=(f"Multiple modules match '{name}': {', '.join(sorted(matches))}"),
        )
    return None

resolve_module_symbol(pkg, dotted, *, source=False)

Try to resolve dotted as module_name.symbol_name.

Tries longest module prefix first (e.g. core.checker before core). Returns None if no module prefix matches.

Source code in packages/axm-ast/src/axm_ast/tools/inspect_resolve.py
Python
def resolve_module_symbol(
    pkg: PackageInfo, dotted: str, *, source: bool = False
) -> ToolResult | None:
    """Try to resolve ``dotted`` as ``module_name.symbol_name``.

    Tries longest module prefix first (e.g. ``core.checker`` before ``core``).
    Returns None if no module prefix matches.
    """
    mod_names = pkg.module_names
    name_to_mod = dict(zip(mod_names, pkg.modules, strict=True))

    parts = dotted.split(".")
    for split_at in range(len(parts) - 1, 0, -1):
        mod_prefix = ".".join(parts[:split_at])
        sym_name = ".".join(parts[split_at:])
        mod = name_to_mod.get(mod_prefix)
        if mod is None:
            continue
        file_rel = relative_path(pkg, mod.path)
        abs_mod = str(mod.path)
        for fn in mod.functions:
            if fn.name == sym_name:
                return ToolResult(
                    success=True,
                    data={
                        "symbol": build_detail(
                            fn,
                            file=file_rel,
                            abs_path=abs_mod,
                            source=source,
                        )
                    },
                )
        for cls in mod.classes:
            if cls.name == sym_name:
                return ToolResult(
                    success=True,
                    data={
                        "symbol": build_detail(
                            cls,
                            file=file_rel,
                            abs_path=abs_mod,
                            source=source,
                        )
                    },
                )
        return ToolResult(
            success=False,
            error=(f"Symbol '{sym_name}' not found in module '{mod_prefix}'"),
        )
    return None

resolve_path(path)

Resolve and validate project path.

Source code in packages/axm-ast/src/axm_ast/tools/inspect_resolve.py
Python
def resolve_path(path: str) -> Path | ToolResult:
    """Resolve and validate project path."""
    project_path = Path(path).resolve()
    if not project_path.is_dir():
        return ToolResult(success=False, error=f"Not a directory: {project_path}")
    return project_path

search_symbols(pkg, *, name=None, returns=None, kind=None, inherits=None)

Search for symbols across a package with filters.

All filters are AND-combined. A symbol must match all provided filters to be included in results.

Parameters:

Name Type Description Default
pkg PackageInfo

Analyzed package info.

required
name str | None

Filter by symbol name (substring match).

None
returns str | None

Filter functions by return type (substring match).

None
kind SymbolKind | None

Filter by SymbolKind (function, method, property, classmethod, staticmethod, abstract, class, variable).

None
inherits str | None

Filter classes by base class name.

None

Returns:

Type Description
list[FunctionInfo | ClassInfo | VariableInfo]

List of matching symbols.

Example

results = search_symbols(pkg, returns="str") [r.name for r in results]['greet', 'version']

Source code in packages/axm-ast/src/axm_ast/core/analyzer.py
Python
def search_symbols(
    pkg: PackageInfo,
    *,
    name: str | None = None,
    returns: str | None = None,
    kind: SymbolKind | None = None,
    inherits: str | None = None,
) -> list[FunctionInfo | ClassInfo | VariableInfo]:
    """Search for symbols across a package with filters.

    All filters are AND-combined. A symbol must match all provided
    filters to be included in results.

    Args:
        pkg: Analyzed package info.
        name: Filter by symbol name (substring match).
        returns: Filter functions by return type (substring match).
        kind: Filter by SymbolKind (function, method, property,
            classmethod, staticmethod, abstract, class, variable).
        inherits: Filter classes by base class name.

    Returns:
        List of matching symbols.

    Example:
        >>> results = search_symbols(pkg, returns="str")
        >>> [r.name for r in results]
        ['greet', 'version']
    """
    results: list[FunctionInfo | ClassInfo | VariableInfo] = []

    for mod in pkg.modules:
        results.extend(
            _search_module(
                mod,
                name=name,
                returns=returns,
                kind=kind,
                inherits=inherits,
            )
        )

    return results