oct
Loading...
Searching...
No Matches
__main__.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# oct/complexity/__main__.py
4
5"""
6Purpose
7-------
8Expose the complexity instrument through ``python -m oct.complexity``.
9
10Responsibilities
11----------------
12- Parse module-command paths and output options.
13- Run the shared measurement service for MAIN-tree probes.
14- Return stable process exit codes for invalid options and missing inputs.
15
16Diagnostics
17-----------
18Domain: OCT-COMPLEXITY
19Levels:
20 L2 - command lifecycle
21 L3 - option and output details
22 L4 - deep tracing
23
24Contracts
25---------
26- Console output is ASCII and JSON mode writes no extra stdout text.
27- The adapter measures and never gates.
28- Human ``--top`` never truncates JSON data.
29
30Dependencies
31------------
32- oct.complexity.service (analysis and rendering)
33- oct.complexity.coverage (missing coverage.py error, reported as exit 2)
34"""
35
36# OCT-LINT: disable-file=dbg_usage reason="Diagnostics would contaminate the module command's JSON-only stdout contract"
37# OCT-LINT: disable-file=dbg_import reason="Diagnostics would contaminate the module command's JSON-only stdout contract"
38
39from __future__ import annotations
40
41import argparse
42import json
43import sys
44from pathlib import Path
45from typing import Sequence
46
47from oct.complexity.coverage import CoverageUnavailableError
48from oct.complexity.service import analyze_paths, render_human
49
50
51def _parser() -> argparse.ArgumentParser:
52 """Build the module command's argument parser."""
53 parser = argparse.ArgumentParser(
54 prog="python -m oct.complexity",
55 description="Measure per-function complexity and optional CRAP scores.",
56 )
57 parser.add_argument(
58 "paths",
59 nargs="*",
60 type=Path,
61 help="Python files or directories (default: current directory).",
62 )
63 parser.add_argument(
64 "--coverage-data",
65 type=Path,
66 default=None,
67 help="Existing coverage.py data file to map offline.",
68 )
69 parser.add_argument(
70 "--json",
71 action="store_true",
72 dest="json_mode",
73 help="Emit the full machine-readable report.",
74 )
75 parser.add_argument(
76 "--top",
77 type=int,
78 default=None,
79 help="Limit human output to the worst N functions.",
80 )
81 return parser
82
83
84def main(argv: Sequence[str] | None = None) -> int:
85 """Run the module command and return its process exit code."""
86 args = _parser().parse_args(argv)
87 if args.top is not None and args.top < 1:
88 print("error: --top must be at least 1", file=sys.stderr)
89 return 2
90 targets = args.paths or [Path.cwd()]
91 try:
92 report = analyze_paths(targets, coverage_data=args.coverage_data)
93 except (CoverageUnavailableError, FileNotFoundError) as exc:
94 print(f"error: {exc}", file=sys.stderr)
95 return 2
96 if args.json_mode:
97 print(json.dumps(report.to_dict(), indent=2, sort_keys=True))
98 else:
99 print(render_human(report, top=args.top))
100 return 0
101
102
103if __name__ == "__main__":
104 raise SystemExit(main())
argparse.ArgumentParser _parser()
Definition __main__.py:51
int main(Sequence[str]|None argv=None)
Definition __main__.py:84