Skip to content

Formatters

formatters

Output formatters for axm-ast.

Provides four output formats (text, JSON, Mermaid, compressed) at three detail levels (summary, detailed, full) with optional budget-based truncation and PageRank-based symbol ranking.

Example

from axm_ast.formatters import format_text output = format_text(pkg, detail="summary") print(output)

filter_modules(pkg, modules)

Return a shallow copy of pkg with modules filtered by name.

Each term in modules is matched as a case-insensitive substring against the dotted module name. If modules is None or empty, the original package is returned unchanged.

Parameters:

Name Type Description Default
pkg PackageInfo

Analyzed package info.

required
modules list[str] | None

Substring filters (OR logic). None means no filter.

required

Returns:

Type Description
PackageInfo

PackageInfo with only matching modules (shallow copy).

Source code in packages/axm-ast/src/axm_ast/formatters.py
def filter_modules(pkg: PackageInfo, modules: list[str] | None) -> PackageInfo:
    """Return a shallow copy of *pkg* with modules filtered by name.

    Each term in *modules* is matched as a case-insensitive substring
    against the dotted module name.  If *modules* is ``None`` or empty,
    the original package is returned unchanged.

    Args:
        pkg: Analyzed package info.
        modules: Substring filters (OR logic).  ``None`` means no filter.

    Returns:
        PackageInfo with only matching modules (shallow copy).
    """
    if not modules:
        return pkg

    from axm_ast.core.analyzer import module_dotted_name

    terms = [t.lower() for t in modules]
    filtered = [
        mod
        for mod in pkg.modules
        if any(t in module_dotted_name(mod.path, pkg.root).lower() for t in terms)
    ]
    return PackageInfo(name=pkg.name, root=pkg.root, modules=filtered)

format_compressed(pkg)

Format package as a compressed AI-friendly summary.

Produces an intermediate format between stub and full: keeps signatures, first docstring line, constants, __all__, and relative imports — drops function bodies, full docstrings, absolute imports, and private symbols (unless in __all__).

Parameters:

Name Type Description Default
pkg PackageInfo

Analyzed package info.

required

Returns:

Type Description
str

Compressed text string.

Example

print(format_compressed(pkg))

Source code in packages/axm-ast/src/axm_ast/formatters.py
def format_compressed(pkg: PackageInfo) -> str:
    """Format package as a compressed AI-friendly summary.

    Produces an intermediate format between ``stub`` and ``full``:
    keeps signatures, first docstring line, constants, ``__all__``,
    and relative imports — drops function bodies, full docstrings,
    absolute imports, and private symbols (unless in ``__all__``).

    Args:
        pkg: Analyzed package info.

    Returns:
        Compressed text string.

    Example:
        >>> print(format_compressed(pkg))
    """
    lines: list[str] = []
    for mod in pkg.modules:
        lines.extend(_compress_module(mod, pkg))
        lines.append("")
    return "\n".join(lines)

format_json(pkg, *, detail='summary')

Format package info as a JSON-serializable dict.

Parameters:

Name Type Description Default
pkg PackageInfo

Analyzed package info.

required
detail DetailLevel

Level of detail — summary, detailed, or full.

'summary'

Returns:

Type Description
dict[str, Any]

JSON-serializable dictionary.

Example

data = format_json(pkg, detail="summary") data["name"] 'sample_pkg'

Source code in packages/axm-ast/src/axm_ast/formatters.py
def format_json(
    pkg: PackageInfo,
    *,
    detail: DetailLevel = "summary",
) -> dict[str, Any]:
    """Format package info as a JSON-serializable dict.

    Args:
        pkg: Analyzed package info.
        detail: Level of detail — ``summary``, ``detailed``, or ``full``.

    Returns:
        JSON-serializable dictionary.

    Example:
        >>> data = format_json(pkg, detail="summary")
        >>> data["name"]
        'sample_pkg'
    """
    result: dict[str, Any] = {
        "name": pkg.name,
        "root": str(pkg.root),
        "module_count": len(pkg.modules),
        "modules": [
            _format_module_json(mod, pkg, detail=detail) for mod in pkg.modules
        ],
    }

    if detail == "full":
        result["dependency_graph"] = build_import_graph(pkg)

    return result

format_mermaid(pkg)

Format the import graph as a Mermaid flowchart.

Parameters:

Name Type Description Default
pkg PackageInfo

Analyzed package info.

required

Returns:

Type Description
str

Mermaid diagram string.

Example

print(format_mermaid(pkg)) graph TD cli --> core

Source code in packages/axm-ast/src/axm_ast/formatters.py
def format_mermaid(pkg: PackageInfo) -> str:
    """Format the import graph as a Mermaid flowchart.

    Args:
        pkg: Analyzed package info.

    Returns:
        Mermaid diagram string.

    Example:
        >>> print(format_mermaid(pkg))
        graph TD
            cli --> core
    """
    graph = build_import_graph(pkg)
    lines = ["graph TD"]

    # Add all modules as nodes
    from axm_ast.core.analyzer import module_dotted_name

    for mod in pkg.modules:
        name = module_dotted_name(mod.path, pkg.root)
        safe_name = name.replace(".", "_")
        lines.append(f'    {safe_name}["{name}"]')

    # Add edges
    for src, targets in graph.items():
        safe_src = src.replace(".", "_")
        for target in targets:
            safe_target = target.replace(".", "_")
            lines.append(f"    {safe_src} --> {safe_target}")

    return "\n".join(lines)

format_module_inspect_text(mod)

Format a single module for human-readable inspect output.

Parameters:

Name Type Description Default
mod ModuleInfo

Module info object.

required

Returns:

Type Description
str

Formatted text string.

Source code in packages/axm-ast/src/axm_ast/formatters.py
def format_module_inspect_text(mod: ModuleInfo) -> str:
    """Format a single module for human-readable inspect output.

    Args:
        mod: Module info object.

    Returns:
        Formatted text string.
    """
    lines: list[str] = [f"📄 {mod.path.name}"]
    summary = parse_docstring(mod.docstring).summary if mod.docstring else None
    if summary:
        lines.append(f"   {summary}")
    lines.append("")
    lines.extend(_format_module_functions(mod))
    lines.extend(_format_module_classes(mod))
    return "\n".join(lines)

format_symbol_text(symbol)

Format a single symbol for human-readable inspect output.

Parameters:

Name Type Description Default
symbol FunctionInfo | ClassInfo

A function or class info object.

required

Returns:

Type Description
str

Formatted text string.

Source code in packages/axm-ast/src/axm_ast/formatters.py
def format_symbol_text(symbol: FunctionInfo | ClassInfo) -> str:
    """Format a single symbol for human-readable inspect output.

    Args:
        symbol: A function or class info object.

    Returns:
        Formatted text string.
    """
    if isinstance(symbol, FunctionInfo):
        lines = _format_function_text(symbol)
    else:
        lines = _format_class_text(symbol)
    return "\n".join(lines)

format_text(pkg, *, detail='summary', budget=None, rank=False)

Format package info as human-readable text.

Parameters:

Name Type Description Default
pkg PackageInfo

Analyzed package info.

required
detail DetailLevel

Level of detail — summary, detailed, or full.

'summary'
budget int | None

Maximum number of output lines. Truncates intelligently.

None
rank bool

When True with a budget, sort symbols by importance (PageRank) so the most relevant appear first.

False

Returns:

Type Description
str

Formatted text string.

Example

text = format_text(pkg, detail="summary") print(text)

Source code in packages/axm-ast/src/axm_ast/formatters.py
def format_text(
    pkg: PackageInfo,
    *,
    detail: DetailLevel = "summary",
    budget: int | None = None,
    rank: bool = False,
) -> str:
    """Format package info as human-readable text.

    Args:
        pkg: Analyzed package info.
        detail: Level of detail — ``summary``, ``detailed``, or ``full``.
        budget: Maximum number of output lines. Truncates intelligently.
        rank: When True with a budget, sort symbols by importance
            (PageRank) so the most relevant appear first.

    Returns:
        Formatted text string.

    Example:
        >>> text = format_text(pkg, detail="summary")
        >>> print(text)
    """
    lines: list[str] = []
    lines.append(f"📦 {pkg.name}")
    lines.append(f"   root: {pkg.root}")
    lines.append(f"   modules: {len(pkg.modules)}")
    lines.append("")

    modules = _rank_modules(pkg) if rank else pkg.modules

    for mod in modules:
        lines.extend(_format_module_text(mod, pkg, detail=detail, rank=rank))
        lines.append("")

    if budget is not None and len(lines) > budget:
        lines = lines[:budget]
        lines.append("... (truncated)")

    return "\n".join(lines)

format_toc(pkg)

Format package as a table-of-contents — module names and counts only.

Returns lightweight module summaries WITHOUT individual function/class details. Useful for agents to decide which modules to drill into.

Parameters:

Name Type Description Default
pkg PackageInfo

Analyzed package info.

required

Returns:

Type Description
list[dict[str, Any]]

List of module dicts with name, docstring, symbol_count,

list[dict[str, Any]]

function_count, class_count.

Example

toc = format_toc(pkg) toc[0]["name"] 'core.analyzer'

Source code in packages/axm-ast/src/axm_ast/formatters.py
def format_toc(pkg: PackageInfo) -> list[dict[str, Any]]:
    """Format package as a table-of-contents — module names and counts only.

    Returns lightweight module summaries WITHOUT individual function/class
    details.  Useful for agents to decide which modules to drill into.

    Args:
        pkg: Analyzed package info.

    Returns:
        List of module dicts with name, docstring, symbol_count,
        function_count, class_count.

    Example:
        >>> toc = format_toc(pkg)
        >>> toc[0]["name"]
        'core.analyzer'
    """
    from axm_ast.core.analyzer import module_dotted_name

    modules: list[dict[str, Any]] = []
    for mod in pkg.modules:
        mod_name = module_dotted_name(mod.path, pkg.root)
        summary = parse_docstring(mod.docstring).summary if mod.docstring else None
        func_count = len(mod.functions)
        cls_count = len(mod.classes)
        modules.append(
            {
                "name": mod_name,
                "docstring": summary,
                "function_count": func_count,
                "class_count": cls_count,
                "symbol_count": func_count + cls_count,
            }
        )
    return modules