Detect and visualize circular imports in Python projects.
Project description
knot
Detect and visualize circular imports in Python projects — fast, static, and dependency-free.
Circular imports are a common source of ImportError and "partially initialized
module" failures, and they quietly couple your code together. knot finds them
without importing or running a single line of your project: it parses the
source with the standard-library ast module, builds the internal module
dependency graph, and reports every cycle with a concrete example path.
It has zero runtime dependencies, runs in CI (non-zero exit on cycles), and can emit a Mermaid diagram of your import graph.
Demo
The
examples/shoppackage intentionally contains a circular import so you can tryknotimmediately:knot examples/shop.
Installation
pip install knot-imports
Or run from a checkout without installing:
PYTHONPATH=src python -m knot path/to/project
Usage
# Analyze the current directory
knot .
# Analyze a specific package or project
knot path/to/your_package
# Exclude directories (repeatable); common ones are skipped by default
knot . --exclude migrations --exclude examples
Example
Given a package where order and customer import each other:
$ knot shop
Analyzed 3 modules, 3 internal imports.
Found 1 import cycle:
1. shop.customer -> shop.order -> shop.customer
Output formats
--format text (default), json, or mermaid:
knot . --format json # machine-readable: summary, cycles, full graph
knot . --format mermaid # a graph LR diagram with cycle nodes highlighted
The Mermaid output pastes directly into a GitHub Markdown ```mermaid block
or the Mermaid Live Editor.
Exit codes
| Code | Meaning |
|---|---|
0 |
No cycles found |
1 |
One or more cycles found |
2 |
Error (e.g. path not found) |
Pass --no-fail to always exit 0 (useful when you only want the report).
Drop knot . into a pre-commit hook or CI step to keep cycles out of main.
How it works
- Discover every
.pyfile under the target and map it to its fully-qualified module name, mirroring how Python would import it. - Parse each file with
astand resolveimport/from ... importstatements (absolute and relative) to internal modules; external imports are ignored. - Detect cycles by computing strongly connected components with an iterative implementation of Tarjan's algorithm (safe on very large graphs), then extract a concrete example path for each cycle.
Development
git clone https://github.com/gazzycodes/knot
cd knot
PYTHONPATH=src python -m unittest discover -s tests -v
The demo GIF is regenerated with python make_demo.py (requires pillow).
Contributions are welcome — please open an issue or PR.
License
MIT — 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 knot_imports-0.1.0.tar.gz.
File metadata
- Download URL: knot_imports-0.1.0.tar.gz
- Upload date:
- Size: 84.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c02a71f7c34d44eb2dd7507840beae4b8b764c270cc6676e1808dc34372a1ce
|
|
| MD5 |
1c32937fb80c405305bd59afd681555d
|
|
| BLAKE2b-256 |
5d0092e17f7377058f50b128820befa1e9726129a42402b7f221245c5a1de757
|
File details
Details for the file knot_imports-0.1.0-py3-none-any.whl.
File metadata
- Download URL: knot_imports-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6eefe68afb4ad84f43594d173b9c671e6987a05ee4d53b498e42c0793942c3dc
|
|
| MD5 |
9935105657aba371f31257ba656626dc
|
|
| BLAKE2b-256 |
677214d374f2cf1c70a090615373d413679f11b8b383bda4a5ce7ce55cae8580
|