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.0.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.0-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: depagon-0.1.0.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.0.tar.gz
Algorithm Hash digest
SHA256 fceddbe874e5a11541f6527987c916e97f69e9da21b9ece637a53352e72531fc
MD5 4232427867cb701d39bbb02fb9b2a4dc
BLAKE2b-256 e5420e648add906ac4766053f8c798e70788a767d04db1dc5ea2c4431cff8459

See more details on using hashes here.

File details

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

File metadata

  • Download URL: depagon-0.1.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 586cfcb008f7f275ab22ae747de5f758e9b62e3caa427f761bb1e6e9f1e04731
MD5 1026868a04c237d7547a5b6502a9ab9c
BLAKE2b-256 7aedee3cf116a634ea4a4c8ba785bb903763a0cf2f980f26323735816f46bc36

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