A Python tool to detect circular imports in your Python projects. This tool analyzes import statements statically and builds a dependency graph to identify circular import cycles that would only be discovered at runtime.
- π Static Analysis: Detects circular imports without running your code
- π― Pre-commit Integration: Prevents circular imports from being committed
- π Detailed Reporting: Shows exactly which files and modules are involved in cycles
- ποΈ Package Support: Handles complex package structures and relative imports
- β‘ Fast: Efficiently processes large codebases
- π‘οΈ Safe: Only analyzes internal project imports, ignores external dependencies
git clone <repository-url>
cd circular-import-detector
pip install -e .pip install circular-import-detector# Check current directory
circular-import-detector
# Check specific directory
circular-import-detector /path/to/your/project
# Quiet mode (only show output if circular imports found)
circular-import-detector --quiet
# Exit with error code if circular imports found (useful for CI/CD)
circular-import-detector --exit-codeFound 1 circular import cycle(s):
Cycle 1:
module_a -> module_b
module_b -> module_c
module_c -> module_a (circular)
Files involved:
module_a: /path/to/project/module_a.py
module_b: /path/to/project/module_b.py
module_c: /path/to/project/module_c.py
The tool is designed to work seamlessly with pre-commit to prevent circular imports from being committed to your repository.
-
Install pre-commit (if you haven't already):
pip install pre-commit
-
Add to your
.pre-commit-config.yaml:
- repo: local
hooks:
- id: circular-imports
name: Check for circular imports (changed files)
entry: circular-import-precommit
language: python
additional_dependencies:
- circular-import-detector==1.0.18
pass_filenames: true
types_or: [python]
stages: [pre-commit]- Install the hooks:
pre-commit install
Now, every time you commit Python files, the tool will check for circular imports and block the commit if any are found.
You can also use the detector in your Python code:
from circular_import_detector import CircularImportDetector
# Initialize detector
detector = CircularImportDetector('/path/to/your/project')
# Detect circular imports
has_cycles, cycles = detector.detect_circular_imports()
if has_cycles:
print(f"Found {len(cycles)} circular import cycles!")
for cycle in cycles:
print("Cycle:", " -> ".join(cycle))
else:
print("No circular imports detected.")The tool performs static analysis of your Python code by:
- Parsing Python files using the
astmodule to extract import statements - Building a dependency graph of modules and their imports
- Filtering internal imports to focus only on your project's modules
- Detecting cycles using depth-first search algorithm
- Reporting results with detailed information about each cycle
import modulefrom module import somethingfrom package.submodule import somethingfrom . import module(relative imports)from ..parent import module(relative imports)
- β
All
.pyfiles in your project - β
Package structures with
__init__.py - β Nested packages and submodules
- β Relative imports within packages
- β External dependencies (ignored)
- β Dynamic imports (not detectable statically)
The tool works out of the box with sensible defaults, but you can customize its behavior:
The detector automatically:
- Skips common non-source directories (
.git,__pycache__,build,dist, etc.) - Handles package structures correctly
- Converts file paths to proper module names
# file_a.py
import file_b
# file_b.py
import file_a # Creates cycle: file_a -> file_b -> file_a# models.py
from views import get_context
# views.py
from utils import helper
# utils.py
from models import MyModel # Creates cycle: models -> views -> utils -> models# package_a/__init__.py
from package_b import something
# package_b/__init__.py
from package_a import something_else # Creates cycle-
"No Python files found"
- Ensure you're running the tool from the correct directory
- Check that your Python files have
.pyextension
-
Relative imports not detected correctly
- Ensure your package structure has proper
__init__.pyfiles - The tool analyzes from the project root you specify
- Ensure your package structure has proper
-
External imports being flagged
- This shouldn't happen, but if it does, the filtering logic may need adjustment
- Open an issue with details about your project structure
- The tool is designed to handle large codebases efficiently
- For very large projects, consider running it on specific subdirectories
- Use
--quietmode in automated environments to reduce output
python -m pytest test_circular_imports.py -v# Test the tool on its own codebase
python circular_import_detector.py .- Fork the repository
- Create a feature branch
- Add tests for your changes
- Ensure all tests pass
- Submit a pull request
MIT License - see LICENSE file for details.