Analyze and visualize complexity hotspots in Python codebases.
Project description
codaviz
A lightweight CLI that analyzes complexity in Python codebases and emits a single, self-contained, interactive HTML report — a simpler, local alternative to SonarQube for spotting where to refactor.
Point it at a repo and it ranks complexity hotspots, draws a treemap (sized by lines of code, colored by a metric you pick), lets you drill into any module to read its functions and source, and flags circular imports and over-threshold functions. No server, no database, no network — the report is one HTML file you can open offline or email to a teammate.
Quick start
codaviz is a uv project. From a checkout:
uv sync # install
uv run codaviz /path/to/project # writes ./report.html
open report.html # (macOS; use xdg-open on Linux)
Try it on codaviz itself:
uv run codaviz . && open report.html
To install it as a standalone command:
uv tool install . # then, anywhere: codaviz /path/to/project
Usage
codaviz [OPTIONS] [PATHS...]
PATHS Project directories to analyze (default: current dir).
Pass several to merge a workspace into one report.
-f, --format html | json | csv (default: html)
-o, --output FILE Output file
(html → report.html; json/csv → stdout unless set)
--no-source Omit embedded source snippets (smaller, shareable report)
--version Show version and exit
-h, --help Show help and exit
Examples:
codaviz ~/src/myapp # interactive report.html
codaviz ~/src/myapp -o myapp.html # custom output path
codaviz ~/src/myapp --no-source -o share.html # no source embedded
codaviz ~/src/myapp -f json > data.json # raw entity data
codaviz ~/src/myapp -f csv > data.csv # one row per package/module/function
codaviz packages/* # merge a workspace into one report
The report
- Treemap — packages and modules as nested tiles, sized by lines of code and colored by the selected metric (packages by their aggregate over all descendants; greener = better). Click a package to zoom in; a depth control caps how many levels show at once so large trees stay readable.
- Metric selector — switch between Maintainability index (default), max/total cyclomatic, max/total cognitive, and lines of code; the treemap, bar chart, and table all re-rank instantly.
- Hotspots table & bar chart — ranked by the selected metric, with LOC / MI / max & total cyclomatic / max & total cognitive / function count. A Modules / Packages toggle switches between per-module rows and package aggregates — so a complex package still stands out even when it's split into many small modules.
- Function detail — click a tile, bar, or row to see that module's functions, each with a CC (cyclomatic) and Cog (cognitive) badge, line number, and source snippet. Functions over either threshold get a "consider extracting" / "hard to follow" hint.
- Circular imports — modules that import each other (statically detected) are listed as cycles.
What gets analyzed
Inside a git repo, codaviz analyzes the Python files git knows about — tracked and uncommitted — while honoring .gitignore (so .venv, build output, and ignored trees are skipped). Outside a repo, it walks the directory. On top of that it always skips common noise: virtualenvs, caches, build/, dist/, node_modules/, site-packages/, migrations/, and test files (tests/, test_*.py, *_test.py, conftest.py) unless you opt in.
Metrics
| Metric | Meaning | Direction |
|---|---|---|
| Cyclomatic (CC) | McCabe complexity — branch/loop count + 1. Per function. Matches Ruff's C901 / python -m mccabe. |
higher = worse |
| Cognitive (Cog) | SonarSource cognitive complexity — penalises nesting, ignores shorthand humans read easily. The better "how hard to understand" signal. Per function. | higher = worse |
| Maintainability index (MI) | radon's 0–100 composite (≥20 = A/good, 10–19 = B, <10 = C). Per module. Kept as the familiar number. | lower = worse |
| SLOC | Source lines of code (excludes blanks/comments). | — (used for tile size) |
Cyclomatic complexity comes from mccabe (so the numbers match Ruff), cognitive from cognitive_complexity, MI + SLOC from radon, and circular imports from a static ast import graph (no code is executed).
Configuration
Optional [tool.codaviz] table in the analyzed project's pyproject.toml:
[tool.codaviz]
exclude = ["generated/*.py", "vendor/**"] # extra glob patterns to skip
max-complexity = 15 # cyclomatic threshold for hints
max-cognitive = 15 # cognitive threshold for hints
treemap-depth = 2 # initial treemap depth (0 = all levels)
include-tests = false # set true to analyze test files too
Known limitations
- Nested defs: closures and methods of function-local classes are folded into their enclosing function's score rather than listed separately — matching how Ruff/mccabe report the outer function.
- Circular imports: resolution favors false negatives over false positives.
src/layouts, implicit namespace packages, and relative imports resolve correctly (names are computed relative to the detected source root); dynamic or conditional imports are not tracked. - Color scale: the badness ramp is green→amber→red with a "better → worse" legend and a numeric table as non-color channels; a fully colorblind-safe palette is a planned option.
Development
make test # uv run pytest
make lint # ruff check + format check + type checks
make format # ruff format + autofix
The test suite spans unit / integration / end-to-end tiers, including in-browser execution of the report's JavaScript via Node.
Status
0.6.0. Stable and usable: hotspots, treemap (with package-level aggregates and tunable depth), drill-down, cyclomatic + cognitive complexity, maintainability index, circular imports, threshold hints, src/-layout and multi-root/workspace analysis, and HTML/JSON/CSV output. Planned next (in rough order): churn-weighted hotspots (complexity × git change-frequency), coupling metrics (afferent/efferent, instability), and trends over time. See notes/ for the vision, spec, and implementation plan, and CHANGES.md for the changelog.
Non-goals
Security scanning (use Bandit), runtime profiling (use cProfile/scalene), and test coverage (use pytest-cov) are out of scope — codaviz focuses on structural complexity.
License
Apache License 2.0 — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file codaviz-0.6.0.tar.gz.
File metadata
- Download URL: codaviz-0.6.0.tar.gz
- Upload date:
- Size: 367.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d70d5b5bd32d20897ecc071b857a74d05bb41baacd68c9ab57ab6774a698579
|
|
| MD5 |
b17c2edef9f03c9744aaf3fa82853529
|
|
| BLAKE2b-256 |
7ea1adb7093c59a31198c6374d7f82d6b5d59890a6796219ef1a2684aa79a571
|
File details
Details for the file codaviz-0.6.0-py3-none-any.whl.
File metadata
- Download URL: codaviz-0.6.0-py3-none-any.whl
- Upload date:
- Size: 374.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cabc18ab1f77a79c5ae6173924d5c1fe2a28c32b2a3b06eb7b661a94449be6d0
|
|
| MD5 |
ccf05bb4dfde9b60808a27321e311fad
|
|
| BLAKE2b-256 |
c144d946e4807536c912e362d709ae1353d7b966548a381c3ee8085e53d77143
|