Skip to main content

Analyze the import dependency structure of a Python project.

Project description

depagon

depagon is a Python CLI tool and library that analyzes the import dependency structure of a Python project. It parses every .py file using the standard-library ast module, builds a directed graph of internal module dependencies, and reports:

  • Circular imports — cycles in the dependency graph.
  • Unused imports — names imported but never referenced in the same file.
  • Coupling metrics — fan-in (how many modules import a given module) and fan-out (how many modules it imports).

It works as both a command-line tool (depagon scan ...) and an importable library.


Install

pip install depagon

Requires Python 3.10 or later. The only runtime dependency is rich.


Usage

Tree output (default)

Renders a dependency tree, coupling table, and findings in the terminal:

depagon scan path/to/myproject

Mermaid diagram

depagon scan path/to/myproject --output mermaid

Outputs a graph TD Mermaid string that can be pasted into any Mermaid-compatible renderer (GitHub Markdown, Mermaid Live Editor, etc.).

Graphviz DOT

depagon scan path/to/myproject --output dot

Outputs a DOT string suitable for dot -Tpng -o graph.png.

Show unused imports

depagon scan path/to/myproject --unused

Unused-import findings are collected during every run but only displayed when --unused is passed.

CI integration — exit code on cycles

depagon scan path/to/myproject --detect-cycles

Exits with status 1 if any circular imports are found, 0 otherwise. Wire it into your CI pipeline:

# GitHub Actions example
- run: depagon scan src/ --detect-cycles

Library usage

from depagon import Analyzer
from depagon.renderers import render_mermaid

result = Analyzer().analyze(Path("src/"))

# Inspect findings
for finding in result.findings:
    print(finding.kind, finding.location, finding.detail)

# Render
print(render_mermaid(result))

Public API:

Symbol Module
Scanner, ImportInfo, ModuleFile depagon.scanner
DependencyGraph depagon.graph
Analyzer, AnalysisResult, Finding depagon.analyzer
render_tree, render_mermaid, render_dot depagon.renderers

All of the above are also re-exported from depagon directly.


Skipped directories

The scanner automatically skips the following directory names to avoid scanning virtual environments and build artifacts:

__pycache__  venv  .venv  env  .env  envs  virtualenv  .virtualenv
node_modules  .tox  .mypy_cache  dist  build  .pytest_cache  .eggs  site-packages

Any directory whose name starts with . (hidden directories) is also skipped.

If your environment uses a different name (e.g. my_env, .project_venv, py310), you can exclude it by subclassing Scanner and overriding _SKIP_DIRS:

from depagon.scanner import Scanner, _SKIP_DIRS

class MyScanner(Scanner):
    pass

# Add your custom env name to the skip set
import depagon.scanner as _s
_s._SKIP_DIRS = _SKIP_DIRS | {"my_env", "py310", ".project_venv"}

Or build the graph programmatically and pass a custom scanner to the analyzer:

from pathlib import Path
import depagon.scanner as scanner_mod
from depagon.scanner import Scanner, _SKIP_DIRS
from depagon.analyzer import Analyzer

# Extend the skip set before scanning
scanner_mod._SKIP_DIRS = _SKIP_DIRS | {"my_env"}

result = Analyzer().analyze(Path("src/"))

How it works

  1. ScanningScanner.scan(root) walks the directory tree (skipping the directories listed above), reads each .py file, and parses it with ast.parse. Files with syntax errors are skipped with a warning. Every import and from ... import statement is recorded as an ImportInfo.

  2. Graph constructionAnalyzer.analyze(root) resolves each import to its absolute dotted module name, checks whether it refers to a file inside the scanned directory (internal module), and adds a directed edge to a DependencyGraph.

  3. Cycle detectionDependencyGraph.find_cycles() uses a colored DFS (white / gray / black) with a recursion stack. When a gray (in-progress) node is encountered again, the slice of the current path forms a cycle. Duplicate cycles are deduplicated via a frozenset key.

  4. Unused-import detection — For each file, ast.walk collects every ast.Name identifier. Any bound import name absent from this set is flagged. This is a conservative heuristic: import os is considered used if os appears anywhere as an identifier in the file.

  5. Rendering — Three renderers produce different output formats from the same AnalysisResult.


Building and publishing

Build a distribution:

pip install build
python -m build

This creates dist/depagon-0.1.0-py3-none-any.whl and a source tarball.

Upload to PyPI (requires a PyPI account and twine):

pip install twine
twine upload dist/*

Running tests

pip install pytest
pytest tests/ -v

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

depagon-0.1.1.tar.gz (104.5 kB view details)

Uploaded Source

Built Distribution

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

depagon-0.1.1-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

Details for the file depagon-0.1.1.tar.gz.

File metadata

  • Download URL: depagon-0.1.1.tar.gz
  • Upload date:
  • Size: 104.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for depagon-0.1.1.tar.gz
Algorithm Hash digest
SHA256 a72201ffee910fe126de7a7d4cfdaf339bbafa6ff6f16a2b8da621195101913d
MD5 f754275b28b29bd2b7974bf3f8e8c354
BLAKE2b-256 2fc9872d93f0030e587ce2673926da0d1a93413f7f6ac7ea175bc1d27cf649ee

See more details on using hashes here.

File details

Details for the file depagon-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: depagon-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 13.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for depagon-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5d9a237a74799121217b25e5637ade292bad9f78ab213d736687804122d2ff23
MD5 505aa8aa67b2de96c7b8de2b1c3561db
BLAKE2b-256 ece5259ff57a02859dfe4fe6472b94f48db165eaf6f08fd7de141a1104362618

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