Skip to main content

A Python import analyzer with cross-file analysis, unused import detection, and autofix

Project description

import-analyzer-py

build status

A Python import analyzer with cross-file analysis, unused import detection, circular import warnings, and autofix.

Comparison with Other Tools

Feature This tool Ruff Autoflake Pyflakes Pylint Unimport
Detect unused imports
Autofix
Cross-file analysis
Re-export tracking ❌¹ ❌²
Cascade detection
Circular import warnings
Unreachable file warnings
Respects __all__ ⚠️³
noqa: F401 support ❌⁴ ✅⁵
Full scope analysis (LEGB) ⚠️⁶ ⚠️⁶
String annotations
TYPE_CHECKING blocks ⚠️⁷
Type comments (# type:)
Redundant alias (x as x)
Star import suggestions
Redefinition warnings
Speed Moderate 🚀 Fast Moderate Fast Slow Moderate

¹ Ruff suggests import X as X for __init__.py but doesn't track actual cross-file usage
² Pylint skips __init__.py by default but doesn't track actual re-export consumers
³ Autoflake only uses __all__ to skip star import expansion, not to preserve re-exports
⁴ Pyflakes has no noqa support; Flake8 adds it as a wrapper layer
⁵ Pylint uses # pylint: disable=unused-import
⁶ Autoflake/Pyflakes have basic scope analysis but miss some LEGB edge cases
⁷ Pyflakes treats TYPE_CHECKING as normal conditional code (works but not explicit)

What makes this tool unique

Cross-file analysis — This is the only tool that follows imports from your entry point and tracks which imports are actually used by other files. This enables:

  • Re-export preservation: If utils.py imports List and main.py does from utils import List, the import in utils.py is correctly identified as used
  • Cascade detection: When removing an unused import makes another import unused, this tool finds all of them in a single pass
  • Circular import detection: Warns about import cycles in your codebase
  • Unreachable file detection: Identifies files that become dead code after fixing imports

Features we don't have (yet)

Based on analysis of other tools' source code:

  • Type comments: # type: int style annotations (PEP 484) are not parsed
  • Redundant alias detection: import X as X as explicit re-export marker (Ruff feature)
  • Star import suggestions: Suggesting specific names to replace from x import * (Unimport feature)
  • Redefinition warnings: Warning when an import is reassigned before use (Pyflakes feature)

Installation

pip install import-analyzer

Or install from source:

git clone https://github.com/cmyui/import-analyzer-py
cd import-analyzer-py
pip install .

Usage

Cross-file mode (default)

Cross-file mode follows imports from an entry point and tracks re-exports across your codebase. This prevents false positives when imports are used by other files.

# Analyze from entry point (follows imports)
import-analyzer main.py

# Analyze entire directory
import-analyzer src/

# Fix all unused imports (including cascaded ones)
import-analyzer --fix main.py

# Warn about implicit re-exports (imports used by other files but not in __all__)
import-analyzer --warn-implicit-reexports main.py

# Warn about circular imports
import-analyzer --warn-circular main.py

# Warn about files that become unreachable after fixing
import-analyzer --warn-unreachable main.py

# Quiet mode (summary only)
import-analyzer -q main.py

Single-file mode

For simple use cases or when you want to analyze files independently:

# Check files independently (no cross-file tracking)
import-analyzer --single-file myfile.py

# Check multiple files
import-analyzer --single-file src/*.py

Exit codes

Code Meaning
0 No unused imports found (or --fix was used)
1 Unused imports found

Features

Cross-file analysis

  • Re-export tracking: Imports used by other files are preserved
  • Cascade detection: Finds all unused imports in a single pass, even when removing one exposes another
  • Circular import detection: Warns about import cycles
  • Implicit re-export warnings: Identifies re-exports missing from __all__
  • Unreachable file detection: Warns about files that become dead code after fixing imports

Single-file analysis

  • Detects unused import X and from X import Y statements
  • Handles aliased imports (import X as Y, from X import Y as Z)
  • Recognizes usage in:
    • Function calls and attribute access
    • Type annotations (including forward references / string annotations)
    • Decorators and base classes
    • Default argument values
    • __all__ exports
  • Skips __future__ imports (they have side effects)
  • Respects # noqa: F401 comments (matches flake8 behavior)
  • Full scope analysis with LEGB rule:
    • Correctly handles function parameters that shadow imports
    • Handles class scope quirks (class body doesn't enclose nested functions)
    • Supports comprehension scopes and walrus operator bindings
    • Respects global and nonlocal declarations

Directory exclusions

The tool automatically skips common non-source directories:

  • Virtual environments: .venv, venv, .env, env
  • Build artifacts: build, dist, *.egg-info
  • Cache directories: __pycache__, .mypy_cache, .pytest_cache, .ruff_cache
  • Version control: .git, .hg, .svn
  • Other: node_modules, .tox, .nox, .eggs

Autofix

  • Safely handles empty blocks by inserting pass
  • Partial removal from multi-import statements
  • Handles semicolon-separated statements
  • Handles backslash line continuations

Examples

Single-file example

Before:

import os
import sys  # unused
from typing import List, Optional  # List unused
from pathlib import Path

def get_home() -> Optional[Path]:
    return Path(os.environ.get("HOME"))

After (--fix):

import os
from typing import Optional
from pathlib import Path

def get_home() -> Optional[Path]:
    return Path(os.environ.get("HOME"))

Cross-file re-export example

# utils.py
from typing import List  # NOT unused - re-exported to main.py

# main.py
from utils import List
x: List[int] = []

Running import-analyzer main.py correctly preserves the List import in utils.py because it's used by main.py.

Cascade detection example

# main.py
from helpers import List  # unused - not used locally

# helpers.py
from utils import List    # becomes unused when main.py's import is removed

# utils.py
from typing import List   # becomes unused when helpers.py's import is removed

Running import-analyzer --fix main.py removes all three imports in a single pass.

noqa comments

The tool respects # noqa comments matching flake8 behavior:

import os  # noqa: F401  - kept (F401 = unused import)
import sys  # noqa       - kept (bare noqa suppresses all)
import re  # noqa: E501  - flagged (wrong code)

For multi-line imports, noqa applies per-line:

from typing import (
    List,  # noqa: F401  - kept
    Dict,  # flagged (no noqa)
)

Known Limitations

  • Star imports: from X import * cannot be analyzed statically
  • Dynamic imports: importlib.import_module() calls are not tracked
  • Namespace packages: PEP 420 namespace packages are not supported

Development

Setup

git clone https://github.com/cmyui/import-analyzer-py
cd import-analyzer-py
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Running tests

# Run with pytest
pytest tests/ -v

# Run with tox (multiple Python versions)
tox

# Run with coverage
tox -e py

Project structure

.
├── import_analyzer/
│   ├── __init__.py          # Public API exports
│   ├── __main__.py          # Entry point for python -m
│   ├── _main.py             # CLI and orchestration
│   ├── _data.py             # Data classes (ImportInfo, ModuleInfo, etc.)
│   ├── _ast_helpers.py      # AST visitors for import/usage collection
│   ├── _detection.py        # Single-file detection logic
│   ├── _autofix.py          # Autofix logic
│   ├── _resolution.py       # Module resolution (resolves imports to files)
│   ├── _graph.py            # Import graph construction
│   ├── _cross_file.py       # Cross-file analysis with cascade detection
│   └── _format.py           # Output formatting
├── tests/
│   ├── detection_test.py
│   ├── aliased_imports_test.py
│   ├── shadowed_imports_test.py
│   ├── scope_analysis_test.py
│   ├── special_imports_test.py
│   ├── type_annotations_test.py
│   ├── autofix_test.py
│   ├── file_operations_test.py
│   ├── cli_test.py
│   ├── resolution_test.py   # Module resolution tests
│   ├── graph_test.py        # Import graph tests
│   ├── cross_file_test.py   # Cross-file analysis tests
│   └── format_test.py       # Output formatting tests
├── pyproject.toml
├── tox.ini
└── .github/workflows/ci.yml

License

MIT

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

import_analyzer_py-0.1.0.tar.gz (35.8 kB view details)

Uploaded Source

Built Distribution

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

import_analyzer_py-0.1.0-py3-none-any.whl (37.5 kB view details)

Uploaded Python 3

File details

Details for the file import_analyzer_py-0.1.0.tar.gz.

File metadata

  • Download URL: import_analyzer_py-0.1.0.tar.gz
  • Upload date:
  • Size: 35.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for import_analyzer_py-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f2298197d2ee68c039b780eac35860eb2d4bd04700b25d737b54b704782c3b54
MD5 136f9488f8ac3d197cb085b15ff340a6
BLAKE2b-256 915abf73e95c5d9d5d37cb70956ae9a55a58780cbfb9451092cba0ee9b7a324e

See more details on using hashes here.

Provenance

The following attestation bundles were made for import_analyzer_py-0.1.0.tar.gz:

Publisher: ci.yml on cmyui/import-analyzer-py

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

File details

Details for the file import_analyzer_py-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for import_analyzer_py-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 92a378251f461763bb6f187f3ba80bfae2db3e4f059e6eca4ca476f906de9109
MD5 13c429bcda870eae3ea1ea25f1bd1eb6
BLAKE2b-256 5547a3d2185682faed64931a5f9d933e418d630a444cfdb8eb56bc0de22d3175

See more details on using hashes here.

Provenance

The following attestation bundles were made for import_analyzer_py-0.1.0-py3-none-any.whl:

Publisher: ci.yml on cmyui/import-analyzer-py

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