Python port of Uncle Bob's crap4go and crap4clj — CRAP score per function for Python source files.
CRAP (Change Risk Anti-Pattern) = CC² × (1 − coverage)³ + CC — a per-function metric combining cyclomatic complexity and branch coverage. Higher means riskier to change. Conventional threshold: 30.
# Run without installing
uvx crap4py
# Persistent install
uv tool install crap4pycrap4py src/ --lcov lcov.infoGenerate lcov.info with coverage.py:
pytest --cov --cov-branch --cov-report=lcov:lcov.infoCRAP Report
Function | Module | CC | Cov% | CRAP
----------------------------+-------------------------------+----+-------+-----
_sort_key | src/crap4py/_crap.py | 3 | 33.3 | 9.9
main | src/crap4py/__main__.py | 2 | 100.0 | 2.0
| Flag | Description |
|---|---|
--lcov PATH |
LCOV branch-coverage file (required) |
--max-crap N |
Exit non-zero if any function exceeds N (CI gate) |
--max-workers N |
Parallel workers for large codebases |
--fragment TEXT |
Only analyse files whose path contains TEXT |
crap4py src/ --lcov lcov.info --max-crap 30Exits non-zero if any function's CRAP score exceeds the threshold. N/A functions (no coverage data) never trip the gate.
- Complexity — cyclomatic complexity from Python's
astperdef/async def - Coverage — branch coverage from LCOV
BRDArecords intersected with each function's line range - Skips —
.gitignore-ignored paths and test files (test_*.py,*_test.py) are excluded automatically