Skip to main content

Offline CLI tool for static analysis of Python repositories

Project description

Repo Inspector

Offline static analysis CLI for Python repositories. No API keys. No internet. Just your code.

License: MIT Python 3.11+ PyPI version

Repo Inspector parses your Python project with the standard library ast module and surfaces code quality metrics, architectural problems, and technical debt — all without touching the network.


Features

  • Cyclomatic complexity — per-function CC scores via Radon, God Object file detection
  • Dead code — heuristic detection of unreferenced functions, classes, and files
  • Module coupling — fan-in / fan-out scores, highlights highly coupled modules
  • Import graph — visualizes the internal dependency tree, detects circular imports
  • Duplicate code — AST-normalized structural similarity hashing
  • Change impact — BFS on the reversed import graph to find blast radius of a change
  • Health score — weighted 0–10 score across six signals (tests, docs, CI, complexity, coupling, dead code)
  • TODO scanner — inventories TODO / FIXME / HACK / NOQA / XXX comments
  • Respects .gitignore — never traverses .git/, __pycache__/, .venv/, dist/

Installation

pip install repo-inspector

Requirements: Python 3.11 or later, no other system dependencies.


Quick Start

# Full analysis summary
repo-inspector scan /path/to/your/project

# With all individual findings printed
repo-inspector scan /path/to/your/project --full

# Export results to JSON
repo-inspector scan /path/to/your/project --output report.json

Example output:

────────────────────── Project Analysis Summary ──────────────────────
   Root path      /path/to/your/project
   Total files    84
   Python files   71
   Lines of code  24,392
   Functions      512
   Classes        73

  Analyzer                Critical  Warning  Info
  Complexity Analysis            0        4     0
  Import Analysis                1        0     0
  Coupling Analysis              0        2     0
  Dead Code Analysis             0        0    18
  Duplication Analysis           0        3     0
  TODO/FIXME Analysis            0        0    11
  Health Analysis                0        1     0

  Health Score  ███████░░░  7.2/10

Commands

Command Description
scan <path> Full analysis summary across all analyzers
complexity <path> Cyclomatic complexity per function, large file detection
deadcode <path> Unused functions, classes, and unreferenced files
coupling <path> Fan-in / fan-out module coupling scores
imports <path> Import graph tree and circular dependency detection
impact <path> <file> Modules affected if a given file changes
health <path> Aggregated repository health score (0–10)
duplication <path> Structurally identical function bodies
todos <path> TODO / FIXME / HACK / NOQA / XXX inventory

Flags

repo-inspector scan . --full          # Print all individual findings after the summary
repo-inspector scan . --output out.json  # Write full results to a JSON file

Thresholds

Metric Warning Critical
Cyclomatic complexity >= 10 >= 20
Function size (lines) >= 50 >= 80
File size (lines) >= 500 >= 1000
Coupling score (fan-in + fan-out) >= 10 >= 20

Health Score Signals

The health command produces a weighted score out of 10. Weights are defined in analysis/health.py.

Signal Weight Description
Test coverage estimate 0.25 Ratio of test files to source files
Avg complexity score 0.20 Inverted average cyclomatic complexity
Documentation ratio 0.20 Functions with docstrings / total functions
CI pipeline present 0.15 .github/workflows/, .gitlab-ci.yml, or Jenkinsfile
Dead code ratio 0.10 Inverted ratio of unreferenced functions
Linting config present 0.10 .flake8, .pylintrc, pyproject.toml [tool.ruff], etc.

How It Works

  1. scan_project() traverses the directory respecting .gitignore, builds a ProjectIndex
  2. Each analyzer receives the immutable ProjectIndex and returns an AnalysisResult
  3. cli.py calls all analyzers and passes results to report/formatter.py for Rich rendering
  4. No analyzer touches the filesystem directly after the index is built

Development Setup

git clone https://github.com/samcab28/Repo-Inspector
cd repo-inspector
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest

Running the test suite

pytest                  # all 211 tests
pytest --tb=short -v    # verbose with short tracebacks
pytest tests/test_complexity.py  # single module

Building the package

python -m build
# Produces:
#   dist/repo_inspector-0.1.0-py3-none-any.whl
#   dist/repo_inspector-0.1.0.tar.gz

Project Structure

repo_inspector/
├── cli.py                    # Typer CLI — all command definitions
├── scanner/
│   └── project_scanner.py    # File traversal, .gitignore handling, ProjectIndex builder
├── analysis/
│   ├── complexity.py         # Cyclomatic complexity, function/file size
│   ├── coupling.py           # Fan-in / fan-out per module
│   ├── deadcode.py           # Unused functions, classes, unreferenced files
│   ├── health.py             # Health score aggregator (weights live here)
│   ├── impact.py             # Change impact via reverse dependency BFS
│   ├── imports.py            # Import graph, circular dependency detection
│   ├── similarity.py         # Duplicate function detection via AST hashing
│   └── todos.py              # TODO/FIXME/HACK/NOQA/XXX comment scanner
├── utils/
│   ├── ast_parser.py         # Dataclasses: ProjectIndex, ModuleInfo, Finding, …
│   └── graph_builder.py      # NetworkX DiGraph construction from ProjectIndex
└── report/
    └── formatter.py          # Rich-based console output (tables, trees, rules)

tests/
├── conftest.py               # Shared fixtures: make_project_index, make_module_info
├── test_integration.py       # End-to-end subprocess tests for every CLI command
├── test_ast_parser.py
├── test_scanner.py
├── test_complexity.py
├── test_coupling.py
├── test_deadcode.py
├── test_health.py
├── test_impact.py
├── test_imports.py
├── test_similarity.py
└── test_todos.py

Architecture Rules

These constraints are enforced by convention and tested indirectly:

  1. Single public function per analyzer: each module in analysis/ exposes exactly analyze(index: ProjectIndex) -> AnalysisResult.
  2. Immutable ProjectIndex: frozen dataclass — no analyzer may mutate it.
  3. No print() in analyzers: all output goes through report/formatter.py.
  4. cli.py is the only cross-layer importer — it imports from both analysis/ and report/; analyzers never import from report/.
  5. NetworkX for all graph workgraph_builder.py returns nx.DiGraph; all cycles/BFS use NetworkX algorithms.

Contributing

Contributions are welcome. Please open an issue before submitting a large change so we can discuss the approach.

# Fork, clone, create a branch
git checkout -b feature/my-analyzer

# Make changes, add tests, confirm the suite passes
pytest --tb=short

# Open a pull request against main

Adding a new analyzer:

  1. Create repo_inspector/analysis/my_analyzer.py with analyze(index) -> AnalysisResult
  2. Add the corresponding tests/test_my_analyzer.py
  3. Import and wire up in cli.py
  4. Add it to the scan command's results dict in cli.py

License

MIT — © 2026 Repo Inspector Contributors

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

repo_inspector-0.1.2.tar.gz (30.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

repo_inspector-0.1.2-py3-none-any.whl (24.5 kB view details)

Uploaded Python 3

File details

Details for the file repo_inspector-0.1.2.tar.gz.

File metadata

  • Download URL: repo_inspector-0.1.2.tar.gz
  • Upload date:
  • Size: 30.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for repo_inspector-0.1.2.tar.gz
Algorithm Hash digest
SHA256 c9d05b505a55c786cbe1f3a321c60b52c8eea5f10f1ed5d07949e984a4fa339b
MD5 2dacf9f063f3a159058fc05eb50a54a7
BLAKE2b-256 9e92d7c5968135bcfe99274f8201cd55622751e81df85deca553bf67293b575b

See more details on using hashes here.

File details

Details for the file repo_inspector-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: repo_inspector-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 24.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for repo_inspector-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c2589793f46489630befaa2508c1019d22b43ba458f3cd6d1400e586b435f031
MD5 07445a8dc60d8c7d22ee4e4f6c6f84f3
BLAKE2b-256 e2d8240158712eadfc12af3687401996f1420971f2b7fc6c9a063b8579931518

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page