Pymetrica is a static analysis tool that computes software engineering metrics for Python codebases.
It parses Python source code using the AST (Abstract Syntax Tree) and evaluates classical metrics used to assess complexity, maintainability, and architectural stability.
The tool provides a modular architecture, a CLI interface, a reusable Python API, and extensible reporting to help developers understand the structural quality of their Python projects.
Repository: https://github.com/JuanJFarina/pymetrica
Analyze a Python project:
pymetrica run-all path/to/project
By default, run-all emits a short terminal report. Use --long-report
when you want descriptive summaries and per-layer breakdowns. Use
-rt BASIC_HOOK when you want thresholds to produce a non-zero exit status
for CI or pre-commit.
Example short report (abridged):
----------------------------------------------------------------------------------------------------
Short Report
----------------------------------------------------------------------------------------------------
Metric: Base Stats
root_folder_path: /path/to/project
root_folder_name: project
folders_number: 0
files_number: 1
lloc_number: 40
...
----------------------------------------------------------------------------------------------------
Metric: Abstract Lines Of Code
aloc_number: 6
aloc_percentage: 15.0
----------------------------------------------------------------------------------------------------
Metric: Cyclomatic Complexity
cc_number: 23
lloc_per_cc: 1.7391304347826086
----------------------------------------------------------------------------------------------------
Metric: Halstead Volume
hv_number: 704.5342159112735
hv_per_lloc: 17.613355397781838
----------------------------------------------------------------------------------------------------
Metric: Primitive Obsession
all_primitives_percent: 0.0
targeted_primitives_percent: 0.0
----------------------------------------------------------------------------------------------------
Metric: Maintainability Cost
maintainability_cost: 50.678396768622775
raw_line_cost: 50.638396768622776
----------------------------------------------------------------------------------------------------
Metric: Instability
root: 0.0
----------------------------------------------------------------------------------------------------
Pymetrica can also analyze architecture layers and dependencies within the codebase.
If you switch to a single-metric command such as pymetrica cc path/to/project,
Pymetrica always prints the descriptive report format instead of this short
layout.
pyproject.tomlpre-commit hooks for automated metric checksSeveral tools compute Python complexity metrics (such as radon, lizard, or SonarQube integrations). Pymetrica focuses on a different goal: architecture-aware metric analysis.
Unlike many static analysis tools, Pymetrica:
This makes it useful not only for measuring complexity, but also for analyzing architectural quality in Python projects.
run-all reports parser-level Base Stats followed by six software engineering
metrics.
Summarizes the resolved analysis root, folder and file counts, logical lines of code, comments, classes, and functions. Base Stats is informational and never contributes to a threshold exit status.
Measures the amount of abstraction and indirection in the codebase by counting abstract constructs such as definitions and structural components.
High ALOC ratios may indicate excessive abstraction or over-engineering.
Measures the number of independent execution paths in a program.
Calculated by analyzing control flow structures including:
Higher values correspond to more complex and harder-to-maintain code.
Measures implementation complexity based on operators and operands used in the program.
Derived from:
The current visitor counts Python AST operators such as assignments, arithmetic and boolean operations, comparisons, control-flow keywords, function and class definitions, and operands such as names, attributes, and constants.
Highlights type annotations that rely heavily on primitive types instead of domain-specific abstractions.
The current implementation counts primitive scalar annotations such as int,
float, bool, str, and Any, plus targeted container annotations such as
dict, list, tuple, and set. Any is also treated as targeted.
PEP 604 | unions are counted when every member resolves to one of the
supported primitive or container forms. Unsupported or custom annotation forms
are ignored rather than reported as primitive usage.
A composite metric derived from:
It estimates the expected maintenance effort required for the codebase. The score combines Halstead density, CC density, and a small LLOC-based size penalty.
Lower scores indicate better maintainability.
Measures package coupling and architectural stability based on import dependencies.
Instability is defined as:
Instability = Efferent Coupling / (Afferent Coupling + Efferent Coupling)
Values range from:
Requires Python 3.10 or newer.
Install the latest published package from PyPI:
Or install from source:
git clone https://github.com/JuanJFarina/pymetrica cd pymetrica pip install -e .
After installation the CLI command becomes available:
Analyze a Python project:
pymetrica run-all path/to/project
All analysis commands default to the current directory, so this is also valid:
Configured [tool.pymetrica].exclude patterns are applied before the codebase
is parsed. To enforce thresholds in automation, use the hook report backend:
pymetrica run-all -rt BASIC_HOOK path/to/project
For an initial overview of a codebase:
To focus on one metric, run its dedicated command:
pymetrica cc path/to/project
Single-metric commands always use the descriptive report format.
pymetrica status
pymetrica base-stats
pymetrica aloc
pymetrica cc
pymetrica hv
pymetrica po
pymetrica mc
pymetrica li
pymetrica run-all
Typical usage pattern:
pymetrica <command> [DIR_PATH]
Notes:
DIR_PATH defaults to the current directoryrun-all supports --long-report for descriptive summaries and per-layer detailaloc, cc, hv, po, mc, and li always emit the descriptive report format[tool.pymetrica].exclude patternsPymetrica reads optional thresholds and exclusion patterns from
[tool.pymetrica] in pyproject.toml:
[tool.pymetrica] aloc_fail_threshold = 30 cc_fail_threshold = 10 hv_fail_threshold = 30 po_all_fail_threshold = 10 po_targeted_fail_threshold = 2 mc_fail_threshold = 25 exclude = ["generated/*", "vendor/*"] top_findings = 5
For CLI commands, configuration discovery starts at DIR_PATH and walks toward
the Git repository root. The nearest pyproject.toml containing
[tool.pymetrica] wins. This allows packages inside a monorepo to define their
own settings. Without a .git marker, the search can continue to the filesystem
root.
Built-in threshold defaults are active: 30 for ALOC, 7 for CC, 30 for
HV, 10 for all primitives, 2 for targeted primitives, and 25 for MC.
Set a threshold to 0 to disable failure gating for that metric. exclude
defaults to an empty list, and top_findings defaults to 5.
Important details:
fnmatchBASIC_HOOK report backend; BASIC_TERMINAL
prints values and exits with 0cc_fail_threshold fails when lloc_per_cc falls below the configured valuerun-all combines threshold failures with exit-code weights 1 for ALOC,
2 for CC, 4 for HV, 8 for MC, and 16 for POBASIC_HOOK return their metric-specific exit
code when the threshold failstop_findings = 0 disables top-finding lists in failure messagesPymetrica also publishes pre-commit hooks:
repos: - repo: https://github.com/JuanJFarina/pymetrica rev: v1.6.0 hooks: - id: pymetrica - id: pymetrica-mc - id: pymetrica-po
Available hook IDs today:
pymetricapymetrica-alocpymetrica-ccpymetrica-hvpymetrica-popymetrica-mcPymetrica is built around a modular analysis pipeline.
Codebase Parsing
↓
Code Representation
↓
Metric Calculators
↓
Results
↓
Report Generators
Core components include:
ParserRecursively scans .py files and builds a structured representation of the codebase.
Extracted information includes:
Files containing syntax errors are automatically skipped.
Core data structures are implemented using Pydantic models.
Main models include:
Code – representation of a Python fileCodebase – full project structureMetric – container for metric metadata and resultsResults – structured metric outputsEach metric is implemented as a subclass of an abstract MetricCalculator.
This design makes it easy to extend the system with additional metrics.
Metrics are rendered through pluggable report generators.
Currently supported:
BASIC_TERMINAL terminal reports, with short and detailed layouts and a
zero exit statusBASIC_HOOK hook-oriented reports that show only failed metrics and return
threshold-based exit statusesJSON machine-readable reports that expose threshold status while retaining
a zero process exit statusFuture formats may include Markdown or file-based outputs.
The CLI and the Python API share the same parser, calculators, and report registry. A typical programmatic workflow is:
from pymetrica.codebase_parser import parse_codebase from pymetrica.metric_calculators import ( AlocCalculator, BaseStatsCalculator, CCCalculator, HalsteadVolumeCalculator, InstabilityCalculator, MaintainabilityCostCalculator, PrimitiveObsessionCalculator, ) from pymetrica.metric_calculators.base_stats import create_diagram from pymetrica.report_generators import REPORTS_MAPPING from pymetrica.utils.settings import update_config_from_pyproject project_path = "path/to/project" update_config_from_pyproject(project_path) codebase = parse_codebase(project_path) metrics = [ BaseStatsCalculator().calculate_metric(codebase), AlocCalculator().calculate_metric(codebase), CCCalculator().calculate_metric(codebase), HalsteadVolumeCalculator().calculate_metric(codebase), PrimitiveObsessionCalculator().calculate_metric(codebase), MaintainabilityCostCalculator().calculate_metric(codebase), InstabilityCalculator().calculate_metric(codebase), ] report_generator = REPORTS_MAPPING["BASIC_TERMINAL"](metrics) print(report_generator.long_report().content) create_diagram(codebase, filename="architecture.mmd")
The CLI loads project configuration automatically. Library callers should call
update_config_from_pyproject() before parse_codebase() when they want the
target project's thresholds and exclusion patterns.
Pymetrica can generate Mermaid diagrams representing the layered architecture of a codebase.
pymetrica base-stats --diagram path/to/project
This creates a .mmd file that can be rendered using:
The diagram focuses on top-level layers and components. Root-level files are
omitted, and __init__.py-style files are not emitted as components.
Tests are implemented using pytest and cover the parser, core metric calculators, diagram generation, and bundled sample codebases.
Run tests with:
Contributions are welcome.
If you want to:
feel free to open an issue or submit a pull request.
MIT License.
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | django-deadcode - dead code analysis tool | 0 | 26.67 | 08-02-2026 |
| 2 | chunkhound - Local first codebase intelligence | 0 | 10 | 24-01-2026 |
| 3 | pytrendy: Trend Detection in Time Series Data | 0 | 10 | 20-06-2026 |
| 4 | vibescore: One-Command Quality Score for Any Python Project | 0 | 22.5 | 30-04-2026 |
| 5 | tallyman: CLI to Summarize Code Size by Language | 0 | 10 | 26-02-2026 |
| 6 | tdb: A Python Debugger Based on Textual | 0 | 10 | 01-06-2026 |
| 7 | DeepSpec - codebase for training and evaluating speculative decoding algorithms | 0 | 10 | 13-07-2026 |
| 8 | supertree: Decision Tree Visualization | 0 | 10 | 13-07-2026 |
| 9 | semantica - Semantic Layer & Knowledge Engineering Framework | 0 | 10 | 08-02-2026 |
| 10 | StegoForge: Zero-Dependency Python Steganography | 0 | 35 | 07-05-2026 |