orchestrata_tools.backcompat.ast_explorer
Reference › orchestrata_tools › backcompat › ast_explorer
This module is a command-line wrapper that keeps the old ast_explorer.py interface alive on top of the orchestrata_tools library. Nothing imports it, and tests/test_orchestrata_tools_backcompat.py covers it.
main parses the legacy flags and loads a serialized AST file (default plans/ast-ultimate.json) with json_loader, then builds an ASTIndex. Each flag prints one report: --summary prints module, class, method and line totals and the counts of abstract and protocol classes; --untested lists untested public methods and --coverage and --gaps print coverage figures and gaps, both using the matcher and analyzer from test_analyzer against a second AST file (default plans/ast-tests.json); --no-docstring, --largest-modules and --class NAME print index queries. --limit caps list length. The flags --stubs and --readiness are declared but have no handler in main. The current command line is __main__.
At a glance
| Source | src/orchestrata_tools/backcompat/ast_explorer.py |
| Lines of code | 89 |
| Classes | 0 |
| Functions | 1 |
| Imports (internal) | orchestrata_tools.parser, orchestrata_tools.test_analyzer |
| Imported by | none |
| Tests that import it | tests/test_orchestrata_tools_backcompat.py |
Class diagram
No classes; see Functions.
Dependency diagram
API
Functions
| Function | Signature | Summary |
|---|---|---|
main |
main(argv: list[str] | None = None) -> int |
Source
#!/usr/bin/env python3
"""Backward-compatible wrapper for ast_explorer.py."""
from __future__ import annotations
import argparse
import sys
from orchestrata_tools.parser import ASTIndex, JSONASTLoader
from orchestrata_tools.test_analyzer import CoverageAnalyzer, TestMatcher
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="AST Codebase Explorer")
parser.add_argument("--ast", default="plans/ast-ultimate.json")
parser.add_argument("--summary", action="store_true")
parser.add_argument("--untested", action="store_true")
parser.add_argument("--test-ast", default="plans/ast-tests.json")
parser.add_argument("--coverage", action="store_true")
parser.add_argument("--gaps", action="store_true")
parser.add_argument("--no-docstring", action="store_true")
parser.add_argument("--largest-modules", action="store_true")
parser.add_argument("--class", dest="class_name")
parser.add_argument("--limit", type=int, default=20)
parser.add_argument("--stubs", action="store_true")
parser.add_argument("--readiness", action="store_true")
args = parser.parse_args(argv)
ast = JSONASTLoader().load(args.ast)
index = ASTIndex(ast)
if args.summary:
print(f"Modules: {len(ast.modules)}")
print(f"Classes: {len(ast.all_classes)}")
print(f"Methods: {len(ast.all_methods)}")
print(f"LOC: {ast.total_loc}")
print(f"Abstract classes: {len(index.abstract_classes())}")
print(f"Protocol classes: {len(index.protocol_classes())}")
if args.untested:
test_ast = JSONASTLoader().load(args.test_ast)
matcher = TestMatcher(test_ast)
untested = matcher.find_untested_methods(index)
print(f"\nUNTESTED PUBLIC METHODS: {len(untested)}")
for m in untested[: args.limit]:
print(f" {m.module_path}.{m.class_name}.{m.name} (line {m.line})")
if args.coverage:
test_ast = JSONASTLoader().load(args.test_ast)
matcher = TestMatcher(test_ast)
analyzer = CoverageAnalyzer(matcher, index)
report = analyzer.analyze()
print(f"\nMethod coverage: {report.method_coverage_pct}%")
print(f"Class coverage: {report.class_coverage_pct}%")
if args.gaps:
test_ast = JSONASTLoader().load(args.test_ast)
matcher = TestMatcher(test_ast)
analyzer = CoverageAnalyzer(matcher, index)
report = analyzer.analyze()
for gap in report.gaps[: args.limit]:
print(f" {gap.module_path}.{gap.class_name}.{gap.method.name}")
if args.no_docstring:
methods = index.methods_without_docstrings()
print(f"\nMethods without docstrings: {len(methods)}")
for m in methods[: args.limit]:
print(f" {m.qualified_name}")
if args.largest_modules:
print("\nLargest modules:")
for path, loc, cc in index.largest_modules(args.limit):
print(f" {path}: {loc} lines, {cc} classes")
if args.class_name:
cls = index.find_class(args.class_name)
if cls:
print(f"\nClass: {cls.name}")
print(f" Module: {cls.module_path}")
print(f" Methods: {cls.method_count}")
print(f" Bases: {cls.bases}")
for m in cls.methods:
print(f" {m.name}()")
return 0
if __name__ == "__main__":
sys.exit(main())