importclean
A production-ready Python import cleaner. Detect and safely remove unused imports from an entire project while preserving code behavior, formatting, and style.
Features
- AST + LibCST analysis - detects every import variant without reformatting unrelated code
- Safe by default - never removes conditional,
TYPE_CHECKING,try/except, or star imports - Partial cleanup - removes only unused names from
from x import a, b, c - Alias detection -
import numpy as npis kept whennpis used - Duplicate removal - collapses repeated identical import statements
- Circular import detection - finds cycles across the whole project
- Dependency graph - renders ASCII trees and Graphviz
.dotfiles - Heavy import suggestions - recommends lazy imports for expensive modules
- Import sorting - PEP 8 / isort-compatible grouping
- Post-clean validation - every modified file is re-parsed and compiled; originals are restored on failure
- Multiprocessing - scales to thousands of files
- Plugin system - add custom rules for project-specific policies
.importclean.tomlconfiguration
Installation
pip install importclean
For development:
git clone https://github.com/Madhav703/importclean
cd importclean
pip install -e ".[dev]"
Quick Start
CLI
importclean .
importclean . --dry-run
importclean . --check
# Show unified diffs
importclean . --diff
# Print import dependency graph
importclean . --graph
# Output results as JSON
importclean . --json
# Print statistics only
importclean . --stats
# Verify all files are syntactically valid
importclean . --verify
# Sort imports in PEP 8 order
importclean . --sort
# Write dependency graph as Graphviz .dot
importclean . --dot graph.dot
# Clean a single file
importclean myfile.py
# Verbose output (per-file details)
importclean . -v
Python API
from importclean import clean_project, clean_file
# Clean an entire project (dry run)
report = clean_project(
path=".",
dry_run=True,
safe_mode=True,
)
print(report.summary())
# Clean a single file
file_report = clean_file("src/mymodule.py", dry_run=False)
print(f"Removed {len(file_report.unused)} unused imports")
Configuration
Create .importclean.toml in your project root:
ignore = [
".venv",
"tests",
"migrations",
]
safe_mode = true
sort_imports = true
remove_unused = true
workers = 4
Safety Guarantees
importclean will never:
- Remove an import that is actually used
- Remove star imports (
from x import *) - Remove
__future__imports - Remove
TYPE_CHECKING-guarded imports - Remove
try/except-wrapped imports - Save a file that fails
ast.parse()orcompile()after transformation - Alter any code outside of import statements
If post-clean validation fails, the original file is restored automatically and the error is reported.
What Gets Removed
| Pattern | Behavior |
|---|---|
import os (unused) |
Removed |
import os (used) |
Kept |
import numpy as np + np.array(...) |
Kept |
from os import path, mkdir (only path used) |
mkdir removed |
from os.path import * |
Never removed |
Duplicate import os |
Second occurrence removed |
if TYPE_CHECKING: from x import T |
Never removed |
try: import ujson as json |
Never removed |
Plugin System
import ast
from typing import Optional
from importclean import clean_project
from importclean.models import ImportInfo
from importclean.plugins.base import BaseRule, RuleResult
from importclean.plugins.registry import PluginRegistry
class NoPickleRule(BaseRule):
name = "no-pickle"
def check(self, node: ImportInfo, tree: ast.Module) -> Optional[RuleResult]:
if node.module == "pickle":
return RuleResult(
import_info=node,
message="Prefer json or msgpack over pickle.",
should_remove=False,
)
return None
registry = PluginRegistry()
registry.register(NoPickleRule)
report = clean_project(".", dry_run=True, registry=registry)
Development
# Run tests
pytest
# Run tests with coverage
pytest --cov=importclean --cov-report=term-missing
# Lint
ruff check importclean tests
# Type check
mypy importclean
# Format
black importclean tests
License
MIT - see LICENSE.
Release files for importclean 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| importclean-0.1.0.tar.gz | 26.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| importclean-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 60.0 kB
Release files / importclean-0.1.0.tar.gz
| Download URL | importclean-0.1.0.tar.gz |
|---|---|
| Size | 26.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fbfca8b21d4eb944f2faa58c189e71c28768686cd4514f233e6d4b6ffce57a60
|
|
BLAKE2b-256 checksum How to use checksums |
e548da17a47364dcfdcaf24507295a1752bc5dbb161fc97913d015c6efdb3785
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / importclean-0.1.0-py3-none-any.whl
| Download URL | importclean-0.1.0-py3-none-any.whl |
|---|---|
| Size | 33.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1c7856a67c1b2810a55b7882702cadb31ab2e873a21856bbb67269395d2bd5ff
|
|
BLAKE2b-256 checksum How to use checksums |
737e246198b7770f72e1a5b960248ce74a41b50b187cc85636214fdf629b8175
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|