orchestrata_tools.main

Reference › orchestrata_tools › main

This module is the command-line entry point of orchestrata_tools, run as python -m orchestrata_tools. Nothing imports it. Every command reads a serialized AST file given by the global --ast option (default plans/ast-ultimate.json) with json_loader and builds an ASTIndex.

There are three subcommands, each handled by one function that returns an exit code:

The same functions exist in older form in backcompat.

At a glance

Source src/orchestrata_tools/__main__.py
Lines of code 151
Classes 0
Functions 4
Imports (internal) orchestrata_tools.diagram, orchestrata_tools.parser, orchestrata_tools.query, orchestrata_tools.test_analyzer
Imported by none
Tests that import it none

Class diagram

No classes; see Functions.

Dependency diagram

Dependency diagram orchestrata_tools.__main__

API

Functions

Function Signature Summary
cmd_discover cmd_discover(args: argparse.Namespace) -> int
cmd_diagram cmd_diagram(args: argparse.Namespace) -> int
cmd_query cmd_query(args: argparse.Namespace) -> int
main main(argv: list[str] | None = None) -> int

Source

Permalink: https://gitlab.com/MSamy/orchestrata-ultimate-architecture/-/blob/a4cbc2bdf/src/orchestrata_tools/__main__.py

"""CLI entry point for orchestrata_tools.

Usage:
    python -m orchestrata_tools discover --ast plans/ast-ultimate.json --untested
    python -m orchestrata_tools diagram --module session.session
    python -m orchestrata_tools query 'methods where tested=false'
"""

from __future__ import annotations

import argparse
import sys

from orchestrata_tools.diagram import ClassDiagramGenerator
from orchestrata_tools.parser import ASTIndex, JSONASTLoader
from orchestrata_tools.query import Query, QueryEvaluator
from orchestrata_tools.test_analyzer import CoverageAnalyzer, TestMatcher


def cmd_discover(args: argparse.Namespace) -> int:
    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}")

    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}")

    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}%")
        print(f"Untested: {len(report.gaps)}")

    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}")

    return 0


def cmd_diagram(args: argparse.Namespace) -> int:
    ast = JSONASTLoader().load(args.ast)
    index = ASTIndex(ast)
    gen = ClassDiagramGenerator(index)

    if args.class_name:
        diagram = gen.generate_for_class(args.class_name)
    elif args.module:
        diagram = gen.generate_for_module(args.module)
    else:
        diagram = gen.generate_full()

    print(diagram.render())
    return 0


def cmd_query(args: argparse.Namespace) -> int:
    ast = JSONASTLoader().load(args.ast)
    index = ASTIndex(ast)

    matcher = None
    if args.test_ast:
        test_ast = JSONASTLoader().load(args.test_ast)
        matcher = TestMatcher(test_ast)

    evaluator = QueryEvaluator(index, matcher)
    # Simple parsing: "methods where tested=false and public=true"
    q = Query().methods()
    if args.where:
        parts = args.where.split(" and ")
        for part in parts:
            if "=" in part:
                key, val = part.split("=", 1)
                key = key.strip()
                val_str = val.strip()
                if val_str == "true":
                    val = True
                elif val_str == "false":
                    val = False
                elif val_str.isdigit():
                    val = int(val_str)
                else:
                    val = val_str
                q = q.where(**{key: val})

    results = evaluator.evaluate(q)
    for r in results[: args.limit]:
        if hasattr(r, "qualified_name"):
            print(r.qualified_name)
        elif hasattr(r, "path"):
            print(r.path)
        else:
            print(r)
    return 0


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(prog="orchestrata_tools")
    parser.add_argument(
        "--ast", default="plans/ast-ultimate.json", help="Path to AST JSON"
    )
    subparsers = parser.add_subparsers(dest="command")

    discover = subparsers.add_parser("discover", help="Discover codebase info")
    discover.add_argument("--summary", action="store_true")
    discover.add_argument("--untested", action="store_true")
    discover.add_argument("--coverage", action="store_true")
    discover.add_argument("--gaps", action="store_true")
    discover.add_argument("--test-ast", default="plans/ast-tests.json")
    discover.add_argument("--limit", type=int, default=20)

    diagram = subparsers.add_parser("diagram", help="Generate Mermaid diagrams")
    diagram.add_argument("--class-name", help="Generate diagram for a class")
    diagram.add_argument("--module", help="Generate diagram for a module")

    query_cmd = subparsers.add_parser("query", help="Query the AST")
    query_cmd.add_argument("where", nargs="?", help="Query filter expression")
    query_cmd.add_argument("--test-ast", default="plans/ast-tests.json")
    query_cmd.add_argument("--limit", type=int, default=20)

    args = parser.parse_args(argv)
    if args.command == "discover":
        return cmd_discover(args)
    elif args.command == "diagram":
        return cmd_diagram(args)
    elif args.command == "query":
        return cmd_query(args)
    else:
        parser.print_help()
        return 1


if __name__ == "__main__":
    sys.exit(main())