Dead Code Eliminator
Overview
Systematically identify unused or redundant code in Python codebases to improve maintainability, reduce confusion, and eliminate technical debt.
Workflow
1. Understand the Scope
Define what to analyze:
Questions to ask:
- What directory or files should be analyzed?
- Should test files be included or excluded?
- Are there specific types of dead code to focus on?
- Should external-facing API functions be considered?
Determine analysis scope:
# Check project structure
ls -la
# Count Python files
find . -name "*.py" | wc -l
# Identify test directories
find . -type d -name "*test*"
2. Identify Dead Code
Use multiple detection strategies to find different types of dead code.
Strategy 1: Find Unused Functions
Use the bundled script for AST-based analysis:
# Scan entire project
python scripts/find_unused_functions.py /path/to/project
# Exclude specific directories
python scripts/find_unused_functions.py /path/to/project tests,venv,docs
What it detects:
- Functions defined but never called
- Methods that aren't invoked anywhere
- Async functions without callers
Limitations:
- Won't detect dynamically called functions (via getattr, decorators)
- May flag public API functions that are used externally
- Doesn't detect pytest fixtures or entry points
Strategy 2: Find Unused Imports
Use the bundled script to identify unused imports:
# Scan single file
python scripts/find_unused_imports.py /path/to/file.py
# Scan entire directory
python scripts/find_unused_imports.py /path/to/project
# Exclude directories
python scripts/find_unused_imports.py /path/to/project venv,.venv,tests
What it detects:
- Imports that are never referenced
- Unused
from X import Ystatements - Redundant imports
Strategy 3: Use External Tools
Leverage Python ecosystem tools for comprehensive analysis:
vulture - Finds unused code:
# Install
pip install vulture
# Run on project
vulture /path/to/project
# Exclude directories
vulture /path/to/project --exclude venv,tests
# Set minimum confidence (0-100)
vulture /path/to/project --min-confidence 80
autoflake - Focuses on imports and variables:
# Install
pip install autoflake
# Check for unused imports
autoflake --check --imports /path/to/file.py
# Check unused imports and variables
autoflake --check --remove-all-unused-imports --remove-unused-variables /path/to/file.py
# Recursive scan
autoflake --check -r /path/to/project
pylint - General linting including dead code:
# Install
pip install pylint
# Check for unused variables, imports, functions
pylint /path/to/project --disable=all --enable=unused-import,unused-variable,unreachable
Strategy 4: Manual Code Review
Read the code to identify patterns:
Unreachable code:
- Code after
returnstatements - Code in impossible conditions
- Code after
break,continue, orraise
Redundant conditions:
- Always-true or always-false checks
- Duplicate conditions
- Unnecessary
elseafterreturn
Look for:
# Find code after return statements (basic pattern)
grep -A 3 "return" **/*.py | grep -v "^--$"
# Find functions with "old" or "legacy" in name
grep -r "def.*old\|def.*legacy" .
# Find TODO comments about removal
grep -r "TODO.*remove\|FIXME.*delete" .
3. Categorize Findings
Organize dead code by type and priority.
See dead-code-patterns.md for comprehensive pattern catalog.
Category: Unused Imports
Priority: High (easy to remove, low risk)
Examples:
import osbut os is never usedfrom typing import List, Dictbut onlyListis used- Duplicate imports
Category: Unused Functions/Methods
Priority: Medium to High
Subcategories:
- Orphaned helpers: Utility functions never called
- Refactoring leftovers: Old implementations not removed
- Test helpers: Test utilities not used by any test
Caution - May be intentional:
- Public API functions (used externally)
- Plugin/hook functions (called dynamically)
- CLI entry points (called from command line)
Category: Unreachable Code
Priority: High (indicates bugs or confusion)
Examples:
- Code after
return - Code in impossible conditions
- Code after
raise
Category: Redundant Code
Priority: Medium
Examples:
- Redundant boolean checks
- Unnecessary
elseafterreturn - Duplicate logic in multiple places
Category: Unused Variables
Priority: Low to Medium
Examples:
- Assigned but never read
- Function parameters never used
- Loop variables never referenced
4. Verify Findings
Before reporting, verify that identified code is truly dead.
Check for dynamic usage:
# Code may appear unused but is called dynamically
handlers = {
'process': process_handler, # Looks unused but isn't
}
# Or via getattr
handler = getattr(module, function_name)
Check for external usage:
- Is this a public API function?
- Is it documented in README or API docs?
- Is it an entry point in setup.py?
Check for framework conventions:
# Django signal handlers
@receiver(post_save, sender=User)
def user_saved(sender, instance, **kwargs): # May appear unused
pass
# Pytest fixtures
@pytest.fixture
def sample_data(): # Used by tests but not "called" directly
return {"key": "value"}
Verify with grep:
# Search for function name in entire codebase
grep -r "function_name" .
# Search in quotes (dynamic calls)
grep -r "'function_name'\|\"function_name\"" .
# Search in setup.py or config files
grep -r "function_name" setup.py pyproject.toml
5. Generate Report
Create a structured markdown report of findings.
Dead Code Analysis Report
Project: [Project Name] Analyzed: [Date] Scope: [Directories analyzed] Excluded: [Excluded directories]
Summary
- Unused imports: X findings across Y files
- Unused functions: A findings across B files
- Unreachable code: M findings
- Redundant code: N findings
Total: Z dead code instances found
🔴 High Priority Issues
Unreachable Code
Code that can never execute - should be removed immediately.
Issue 1: Code After Return
Location: src/utils.py:45-47
Code:
def process_data(data):
if not data:
return None
logging.warning("Empty data") # UNREACHABLE
validate(data) # UNREACHABLE
Recommendation: Remove lines 46-47 (unreachable after return).
Impact: Misleading code that suggests validation happens but doesn't.
Unused Imports
File: src/main.py
Lines:
- Line 3:
import os(unused) - Line 5:
from typing import Dict, Tuple(onlyDictis used) - Line 12:
import re(unused)
Recommendation: Remove unused imports. Update line 5 to from typing import Dict.
🟡 Medium Priority Issues
Unused Functions
Functions that appear unused but should be verified before removal.
Issue 3: Orphaned Helper Function
Location: src/helpers.py:89
Function: format_timestamp(ts: int) -> str
Analysis:
- Defined but never called in codebase
- Not in public API documentation
- Not an entry point
Verification needed:
- ✅ Checked: Not in setup.py entry_points
- ✅ Checked: Not mentioned in README
- ✅ Checked: No string references in codebase
- ❌ Need to verify: Could this be used by external code?
Recommendation: If not part of public API, remove. Otherwise, document it.
Issue 4: Duplicate Logic
Locations:
src/processor_a.py:45-52src/processor_b.py:78-85
Code: Both files contain identical validation logic.
Recommendation: Extract common logic into shared utility function.
Impact: Maintenance burden - changes must be duplicated.