Skip to content

Inspect Resolve Helpers

Internal resolution helpers. Use ast_inspect for the request/response interface. Missing and ambiguous symbols are errors; batch callers should check individual entries. Module source is truncated to 200 lines.

Signatures and docstrings below are rendered from the checkout during the build.

inspect_module

inspect_module(pkg, name, *, source=False)

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, *, source: bool = False
) -> 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)
    if source:
        try:
            text = mod.path.read_text(encoding="utf-8")
            lines = text.splitlines(keepends=True)
            if len(lines) > _MAX_SOURCE_LINES:
                hidden = len(lines) - _MAX_SOURCE_LINES
                kept = "".join(lines[:_MAX_SOURCE_LINES]).rstrip("\n")
                text = f"{kept}\n… (+{hidden} lines truncated)\n"
            detail["source"] = text
        except OSError:
            pass
    return ToolResult(
        success=True, data={"symbol": detail}, text=render_module_text(detail)
    )

resolve_module_symbol

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:
                detail = build_detail(
                    fn, file=file_rel, abs_path=abs_mod, source=source
                )
                return ToolResult(
                    success=True,
                    data={"symbol": detail},
                    text=render_symbol_text(detail),
                )
        for cls in mod.classes:
            if cls.name == sym_name:
                detail = build_detail(
                    cls, file=file_rel, abs_path=abs_mod, source=source
                )
                return ToolResult(
                    success=True,
                    data={"symbol": detail},
                    text=render_symbol_text(detail),
                )
        return ToolResult(
            success=False,
            error=(f"Symbol '{sym_name}' not found in module '{mod_prefix}'"),
        )
    return None

InspectTool.execute

execute(*, path='.', symbol=None, symbols=None, source=False, **kwargs)

Inspect a symbol by name.

Parameters:

Name Type Description Default
path str

Path to package directory.

'.'
symbol str | None

Symbol name to inspect (required if symbols is not provided). Supports dotted paths like ClassName.method.

None
symbols list[str] | None

Optional list of symbol names for batch inspection.

None
source bool

If True, include source code in the response.

False

Returns:

Type Description
ToolResult

ToolResult with symbol details.

Source code in packages/axm-ast/src/axm_ast/tools/inspect.py
Python
@safe_execute
def execute(
    self,
    *,
    path: str = ".",
    symbol: str | None = None,
    symbols: list[str] | None = None,
    source: bool = False,
    **kwargs: object,
) -> ToolResult:
    """Inspect a symbol by name.

    Args:
        path: Path to package directory.
        symbol: Symbol name to inspect (required if symbols is not provided).
            Supports dotted paths like ``ClassName.method``.
        symbols: Optional list of symbol names for batch inspection.
        source: If True, include source code in the response.

    Returns:
        ToolResult with symbol details.
    """
    if not symbol and not symbols:
        return ToolResult(
            success=False, error="symbol or symbols parameter is required"
        )

    source = bool(source)

    project_path = resolve_path(path)
    if isinstance(project_path, ToolResult):
        return project_path

    try:
        if symbols is not None:
            return self._inspect_batch(project_path, symbols, source=source)

        return self._inspect_symbol(project_path, symbol, source=source)  # type: ignore[arg-type]
    except Exception as exc:  # noqa: BLE001
        return ToolResult(success=False, error=str(exc))

_inspect_symbol

_inspect_symbol(project_path, symbol, *, source=False)

Resolve a simple or dotted symbol name to inspect details.

For a simple name, the exact-name match is preferred: search_symbols matches on substring, so a request for Foo would otherwise also pick a superset like FooBar. The exact match wins; when several symbols share the requested name across modules, a disambiguation error is returned; when none match exactly, resolution falls through to the module fallback (never a substring superset).

Source code in packages/axm-ast/src/axm_ast/tools/inspect.py
Python
def _inspect_symbol(
    self, project_path: Path, symbol: str, *, source: bool = False
) -> ToolResult:
    """Resolve a simple or dotted ``symbol`` name to inspect details.

    For a simple name, the exact-name match is preferred: ``search_symbols``
    matches on substring, so a request for ``Foo`` would otherwise also pick
    a superset like ``FooBar``. The exact match wins; when several symbols
    share the requested name across modules, a disambiguation error is
    returned; when none match exactly, resolution falls through to the
    module fallback (never a substring superset).
    """
    from axm_ast.core.analyzer import search_symbols
    from axm_ast.core.cache import get_package

    pkg = get_package(project_path)

    if "." in symbol:
        from axm_ast.tools.dependency import inspect_with_dependencies

        return inspect_with_dependencies(pkg, symbol, source=source)

    # --- Simple name: function or class ---
    results = search_symbols(
        pkg,
        name=symbol,
        returns=None,
        kind=None,
        inherits=None,
    )

    # `search_symbols` matches on substring, so a request for ``Foo`` also
    # returns supersets like ``FooBar``. Prefer the exact-name match; never
    # silently pick a substring superset (mirrors ``resolve_module``).
    exact = [(mod, sym) for mod, sym in results if sym.name == symbol]

    candidates = sorted({f"{mod}.{symbol}" for mod, _ in exact})
    if len(candidates) > 1:
        return ToolResult(
            success=False,
            error=format_ambiguous_symbol_error(symbol, candidates),
        )

    if not exact:
        # --- Module fallback ---
        mod_result = inspect_module(pkg, symbol, source=source)
        if mod_result is not None:
            return mod_result
        return ToolResult(
            success=False,
            error=f"Symbol '{symbol}' not found",
        )

    _, sym = exact[0]
    file_path = find_symbol_file(pkg, sym)
    abs_path = find_symbol_abs_path(pkg, sym)
    detail = build_detail(sym, file=file_path, abs_path=abs_path, source=source)
    return ToolResult(
        success=True,
        data={"symbol": detail},
        text=render_symbol_text(detail),
    )

resolve_class_method

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)
    detail = build_detail(method, file=file_path, abs_path=abs_path, source=source)
    return ToolResult(
        success=True,
        data={"symbol": detail},
        text=render_symbol_text(detail),
    )

InspectTool._inspect_batch

_inspect_batch(project_path, symbols, *, source)

Inspect multiple symbols in batch.

Source code in packages/axm-ast/src/axm_ast/tools/inspect.py
Python
def _inspect_batch(
    self,
    project_path: Path,
    symbols: list[str],
    *,
    source: bool,
) -> ToolResult:
    """Inspect multiple symbols in batch."""
    if not isinstance(symbols, list):
        return ToolResult(success=False, error="symbols parameter must be a list")
    results: list[dict[str, object]] = []
    for sym in symbols:
        res = self._inspect_symbol(project_path, sym, source=source)
        if res.success and res.data and "symbol" in res.data:
            results.append(cast("dict[str, object]", res.data["symbol"]))
        else:
            results.append({"name": sym, "error": res.error})
    try:
        text = render_batch_text(results)
    except (KeyError, TypeError):
        text = None
    return ToolResult(
        success=True,
        data={"symbols": results},
        text=text,
    )