A tool to detect circular imports in Python projects
Project description
Circular Import Detector
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.
Features
- 🔍 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
Installation
From Source
git clone <repository-url>
cd circular-import-detector
pip install -e .
Using pip (when published)
pip install circular-import-detector
Usage
Command Line Interface
Basic Usage
# 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-code
Example Output
Found 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
Pre-commit Hook Integration
The tool is designed to work seamlessly with pre-commit to prevent circular imports from being committed to your repository.
Setup
-
Install pre-commit (if you haven't already):
pip install pre-commit
-
Add to your
.pre-commit-config.yaml:repos: - repo: local hooks: - id: circular-imports name: Check for circular imports entry: python precommit_hook.py language: system files: \.py$ pass_filenames: true
-
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.
Programmatic Usage
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.")
How It Works
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
Supported Import Types
import modulefrom module import somethingfrom package.submodule import somethingfrom . import module(relative imports)from ..parent import module(relative imports)
What Gets Analyzed
- ✅ 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)
Configuration
The tool works out of the box with sensible defaults, but you can customize its behavior:
Project Structure
The detector automatically:
- Skips common non-source directories (
.git,__pycache__,build,dist, etc.) - Handles package structures correctly
- Converts file paths to proper module names
Custom Pre-commit Configuration
You can customize the pre-commit hook behavior:
repos:
- repo: local
hooks:
- id: circular-imports
name: Check for circular imports
entry: python precommit_hook.py --project-root .
language: system
files: \.py$
pass_filenames: true
args: ['--project-root', '.']
Common Circular Import Patterns
Simple Cycle
# file_a.py
import file_b
# file_b.py
import file_a # Creates cycle: file_a -> file_b -> file_a
Complex Cycle
# 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 Cycle
# package_a/__init__.py
from package_b import something
# package_b/__init__.py
from package_a import something_else # Creates cycle
Troubleshooting
Common Issues
-
"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
Performance Tips
- 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
Development
Running Tests
python -m pytest test_circular_imports.py -v
Running the Tool on Itself
# Test the tool on its own codebase
python circular_import_detector.py .
Contributing
- Fork the repository
- Create a feature branch
- Add tests for your changes
- Ensure all tests pass
- Submit a pull request
License
MIT License - see LICENSE file for details.
Changelog
v1.0.0
- Initial release
- Basic circular import detection
- Pre-commit hook integration
- Comprehensive test suite
- CLI interface with multiple options
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 circular_import_detector-1.0.3.tar.gz.
File metadata
- Download URL: circular_import_detector-1.0.3.tar.gz
- Upload date:
- Size: 14.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
40cc52d3c8fb6c1fe5c11ef0dba2eb97558827bf11fd295a915d2789bae4e7a1
|
|
| MD5 |
873ca95e8d005944c4296206da639016
|
|
| BLAKE2b-256 |
278bb0715cdd86a56bd12a7f7d893216815307bb0308bde6f1d5dc7e34cadacd
|
File details
Details for the file circular_import_detector-1.0.3-py3-none-any.whl.
File metadata
- Download URL: circular_import_detector-1.0.3-py3-none-any.whl
- Upload date:
- Size: 14.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
218bd867e7b5554ce919bb030af356281e6d0a4cb655ea719086737b1178dc83
|
|
| MD5 |
09ad3ebdfd4e67d8dcbfd18b3574264f
|
|
| BLAKE2b-256 |
43c5a948e30cc69d9279615622aa75891be6b962c1da4bac7b94b61985b2b942
|