Skip to main content

Dependency graph and boundary enforcement for Python Polylith workspaces.

Project description

polydep

Dependency graph and boundary enforcement for Python Polylith workspaces.

polydep analyzes inter-brick imports in a Python Polylith monorepo and outputs a Mermaid dependency graph. It complements the poly CLI by adding graph visualization, dependency chain explanation, and CI-friendly boundary checks.

Mostly read-only — polydep project --fix can rewrite [tool.polylith.bricks] sections.

Install

pip install polydep
# or
uv tool install polydep

Requires Python 3.11+.

Quick start

# Open the dependency graph in an interactive browser viewer
polydep graph --view

# Generate a dependency graph as Mermaid
polydep graph

# Specify a workspace root
polydep graph --root /path/to/workspace

# Save to polydep.expected.mermaid
polydep graph --save

Example output:

graph LR
  subgraph bases
    consumer
    greet_api
    message_api
  end
  subgraph components
    database
    dictionaries
    greeting
    kafka
    log
    message
    schema
  end
  consumer --> kafka
  consumer --> log
  greet_api --> greeting
  greet_api --> log
  kafka --> log
  message --> database
  message --> dictionaries
  message --> kafka
  message --> schema
  message_api --> database
  message_api --> log
  message_api --> message
  message_api --> schema

Commands

polydep graph

Print the dependency graph as a Mermaid diagram to stdout.

polydep graph [--root <path>] [--save] [--view]
Flag Default Description
--root <path> . Workspace root directory
--save Write to polydep.expected.mermaid instead of printing
--view Open the graph in an interactive browser viewer
--no-ignore Scan all files, ignoring .gitignore rules

--view and --save can be combined: saves the Mermaid file and opens the viewer.

polydep view

Open a saved Mermaid diagram in the interactive browser viewer.

polydep view [<file>]
Argument Default Description
<file> polydep.expected.mermaid Path to a .mermaid file

The viewer renders an interactive graph with transitive node highlighting, search, cycle detection, and connected-component grouping. The tab title and sidebar logo show the workspace namespace (e.g. myapp) — inferred from the workspace.toml in the same directory as the file.

polydep why

Explain why brick A depends on brick B — shows all dependency paths with exact file and line provenance.

polydep why <source_brick> <target_brick> [--root <path>] [--no-ignore]
Flag Default Description
--root <path> . Workspace root directory
--no-ignore Scan all files, ignoring .gitignore rules

Example output:

consumer depends on log via 2 paths:

Path 1 (direct):
  consumer -> log
    bases/example/consumer/core.py:3  from example import kafka, log

Path 2 (transitive, length 2):
  consumer -> kafka -> log
    bases/example/consumer/core.py:3  from example import kafka, log
    components/example/kafka/consumer.py:5  from example import log
    components/example/kafka/producer.py:3  from example import log

polydep project

Check that each project's pyproject.toml declares exactly the bricks it needs — no missing, no stale extras. Computes the full transitive closure from the project's base bricks.

polydep project [<project_path>] [--fix] [--root <path>]
Flag Default Description
<project_path> Single project directory to check (omit to scan all projects/*/)
--fix Rewrite [tool.polylith.bricks] with the correct set
--root <path> . Workspace root directory

Example output (issues found):

consumer_app: 2 issue(s)
  Missing (needed but not declared):
    log
  Extra (declared but not needed):
    greeting
messaging: OK

The --fix flag rewrites the bricks section in place, grouping entries into # direct (base bricks and their immediate imports) and # transitive (everything else), with # via annotations showing which bricks pull each transitive one in:

[tool.polylith.bricks]
# direct
"../../bases/example/message_api" = "example/message_api"
"../../components/example/database" = "example/database"
"../../components/example/log" = "example/log"
"../../components/example/message" = "example/message"
"../../components/example/schema" = "example/schema"

# transitive
"../../components/example/dictionaries" = "example/dictionaries"  # via message
"../../components/example/kafka" = "example/kafka"  # via message
Exit code Meaning
0 All projects OK (or --fix applied)
1 Issues found (without --fix)

polydep check

Compare actual dependencies against an expected graph file. Designed for CI — exits non-zero on mismatch.

polydep check [--expected <path>] [--root <path>] [--no-cycles]
Flag Default Description
--expected <path> polydep.expected.mermaid Path to expected graph file
--root <path> . Workspace root directory
--no-ignore Scan all files, ignoring .gitignore rules
--no-cycles Fail if the dependency graph contains any circular dependencies

The expected graph file is a Mermaid file, typically generated by polydep graph --save. Strict comparison — unexpected edges (boundary violations) and missing edges (stale graph) cause failure. Unexpected edges include file and line provenance.

--no-cycles adds a circular-dependency gate that runs before the Mermaid comparison. It detects every cycle — direct and transitive — in the actual dependency graph and fails if any exist, so a cycle breaks the build even if its edges are declared in the expected file. When the graph is acyclic, the Mermaid comparison runs as usual, letting one polydep check --no-cycles invocation enforce both in CI:

Check failed.

Circular dependencies detected:
  alpha -> beta -> alpha
  message -> kafka -> message

When the graph matches:

Check passed.

When there are violations:

Check failed.

Unexpected dependencies:
  consumer --> database
    bases/example/consumer/core.py:3  from example import database, kafka, log

Missing dependencies:
  greet_api --> log
Exit code Meaning
0 Actual graph matches expected graph
1 Mismatch detected
2 Error (file not found, parse error, etc.)

CI integration

Bootstrap an expected graph

polydep graph --save
git add polydep.expected.mermaid && git commit -m "Add expected dependency graph"

GitHub Actions

- uses: astral-sh/setup-uv@v5
- run: uv tool install polydep
- run: polydep check

Pre-commit hook

# .pre-commit-config.yaml
- repo: local
  hooks:
    - id: polydep-check
      name: polydep boundary check
      entry: uv run polydep check
      language: system
      pass_filenames: false

How it works

  1. Workspace discovery — finds workspace.toml (or pyproject.toml with [tool.polylith]) and reads the namespace
  2. Brick enumeration — scans components/<namespace>/*/ and bases/<namespace>/*/, respecting .gitignore files at any level (pass --no-ignore to disable)
  3. Import extraction — parses every .py file with Python's ast module, collecting all absolute imports (relative imports are skipped as they're internal to a brick)
  4. Graph construction — filters imports to those targeting known bricks (matching <namespace>.<brick_name>), excludes self-imports, and builds a deduplicated edge set
  5. Output — renders the graph as a Mermaid diagram with subgraph grouping by brick type

Comparison with poly CLI

Feature poly CLI polydep
Dependency table poly deps --
Dependency graph (Mermaid) -- polydep graph
Interactive graph viewer -- polydep graph --view, polydep view
Dependency explanation -- polydep why
Boundary enforcement -- polydep check
Missing/extra deps in project poly check polydep project
Library analysis poly libs --

polydep complements rather than replaces poly. It focuses on the inter-brick dependency graph.

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

polydep-0.1.16.tar.gz (220.3 kB view details)

Uploaded Source

Built Distribution

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

polydep-0.1.16-py3-none-any.whl (199.9 kB view details)

Uploaded Python 3

File details

Details for the file polydep-0.1.16.tar.gz.

File metadata

  • Download URL: polydep-0.1.16.tar.gz
  • Upload date:
  • Size: 220.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for polydep-0.1.16.tar.gz
Algorithm Hash digest
SHA256 57e7b463ef46a8eb4357eda027beae00014ab8fe1aec4865bf3c12248ee995bc
MD5 52c8978c7adfe4163b4f6f6fc6f65ed0
BLAKE2b-256 26eb4b13a2eae37f77466672eb06a9e968fa6a177b6105be0c65a1ff88b3e4ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for polydep-0.1.16.tar.gz:

Publisher: ci.yml on aulme/polydep

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file polydep-0.1.16-py3-none-any.whl.

File metadata

  • Download URL: polydep-0.1.16-py3-none-any.whl
  • Upload date:
  • Size: 199.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for polydep-0.1.16-py3-none-any.whl
Algorithm Hash digest
SHA256 6d40d3a675318f52ebaa0c20797b5ab98aaeb3d73f43b31af5b6669acade0198
MD5 2ecb1bd7fe6e71b0db6cb13e01f9cb36
BLAKE2b-256 7bf60fa99d29570ae52d40b5ab37d43524d35bcd431f965e6255c99f51d50283

See more details on using hashes here.

Provenance

The following attestation bundles were made for polydep-0.1.16-py3-none-any.whl:

Publisher: ci.yml on aulme/polydep

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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