vulture-dead-code
33
总安装量
7
周安装量
#11176
全站排名
安装命令
npx skills add https://github.com/laurigates/claude-plugins --skill vulture-dead-code
Agent 安装分布
opencode
5
github-copilot
5
claude-code
4
kiro-cli
4
cursor
4
Skill 文档
Vulture and deadcode – Dead Code Detection
Tools for finding unused Python code including functions, classes, variables, imports, and attributes.
Overview
Vulture (mature, confidence-based) and deadcode (newer, AST-based) both detect unused code but with different approaches:
| Feature | Vulture | deadcode |
|---|---|---|
| Approach | Static analysis + confidence scores | AST-based detection |
| Accuracy | Confidence scores (60-100%) | High accuracy, fewer false positives |
| Speed | Fast | Very fast |
| Configuration | Whitelist files | TOML configuration |
| Maturity | Mature (2012) | Newer (2023+) |
| Best For | Large codebases, gradual cleanup | New projects, strict enforcement |
Installation
# Install vulture
uv add --dev vulture
# Install deadcode (newer alternative)
uv add --dev deadcode
# Install both for comparison
uv add --dev vulture deadcode
Vulture – Confidence-Based Detection
Basic Usage
# Check entire project
vulture .
# Check specific files/directories
vulture src/ tests/
# Minimum confidence threshold (60-100%)
vulture --min-confidence 80 .
# Exclude patterns
vulture . --exclude "**/migrations/*,**/tests/*"
# Sort by confidence
vulture --sort-by-size .
# Generate whitelist of current issues
vulture . --make-whitelist > vulture_whitelist.py
Configuration
pyproject.toml Configuration
[tool.vulture]
# Minimum confidence to report (60-100%)
min_confidence = 80
# Paths to scan
paths = ["src", "tests"]
# Exclude patterns (glob)
exclude = [
"**/migrations/*",
"**/__pycache__/*",
"**/node_modules/*",
".venv/*"
]
# Ignore decorators (marks functions as used)
ignore_decorators = [
"@app.route",
"@pytest.fixture",
"@property",
"@staticmethod",
"@classmethod"
]
# Ignore names matching patterns
ignore_names = [
"test_*", # Test functions
"setUp*", # Test setup
"tearDown*", # Test teardown
]
# Make whitelist
make_whitelist = false
# Sort results
sort_by_size = false
vulture_whitelist.py Pattern
# vulture_whitelist.py
# Whitelist for false positives
# Used by external code
_.used_by_external_lib # confidence: 60%
MyClass.called_dynamically # confidence: 60%
# Used in templates
def render_template_helper():
pass # confidence: 60%
# Used via __getattr__
dynamic_attribute = None # confidence: 60%
# Framework magic
class Meta: # Django/Flask metadata
pass
# Plugin system
def plugin_hook(): # Called by plugin system
pass
Understanding Confidence Scores
# 100% confidence (definitely unused)
def never_called():
"""This function is never called anywhere."""
pass
# 80% confidence (likely unused)
def maybe_called():
"""Called in commented code or string."""
pass
# 60% confidence (possibly unused)
def dynamic_call():
"""Might be called via getattr() or string."""
pass
# Set minimum confidence threshold
# --min-confidence 80 = Report only high-confidence issues
# --min-confidence 60 = Report all potential issues (more false positives)
Common Patterns
Unused Imports
# FOUND: Unused import
import sys # confidence: 100%
import os # confidence: 100%
# USED: Import is used
import logging
logger = logging.getLogger(__name__)
Unused Functions
# FOUND: Unused function
def unused_helper(): # confidence: 100%
return 42
# USED: Function is called
def used_helper():
return 42
result = used_helper()
Unused Class Attributes
class MyClass:
# FOUND: Unused attribute
unused_attr = 42 # confidence: 100%
# USED: Attribute is accessed
used_attr = 42
def method(self):
return self.used_attr
Unused Variables
def process():
# FOUND: Unused variable
unused = calculate() # confidence: 100%
# USED: Variable is used
result = calculate()
return result
False Positives (When to Whitelist)
# 1. Dynamic attribute access
class Config:
DEBUG = True # Accessed via getattr(config, 'DEBUG')
# 2. Framework magic
class Meta: # Used by Django ORM
db_table = 'users'
# 3. Decorators
@app.route('/api/data')
def api_endpoint(): # Route handler - appears unused
pass
# 4. Test fixtures
@pytest.fixture
def sample_data(): # Fixture - appears unused
return [1, 2, 3]
# 5. Plugin hooks
def plugin_initialize(): # Called by plugin system
pass
# 6. Serialization
class User:
def to_dict(self): # Called by serialization library
pass
Gradual Cleanup Strategy
# Step 1: Generate baseline
vulture --make-whitelist > vulture_whitelist.py
# Step 2: Fix high-confidence issues
vulture --min-confidence 90 .
# Step 3: Lower threshold gradually
vulture --min-confidence 80 .
vulture --min-confidence 70 .
# Step 4: Update whitelist
vulture --make-whitelist > vulture_whitelist.py
# Step 5: Enforce in CI
vulture --min-confidence 80 .
deadcode – AST-Based Detection
Basic Usage
# Check entire project
deadcode .
# Check specific files/directories
deadcode src/
# Verbose output
deadcode --verbose .
# Dry run (show what would be removed)
deadcode --dry-run .
# Show unreachable code
deadcode --show-unreachable .
# Generate configuration
deadcode --init
Configuration
pyproject.toml Configuration
[tool.deadcode]
# Paths to scan
paths = ["src"]
# Exclude patterns
exclude = [
"tests/*",
"**/__pycache__/*",
"**/migrations/*",
]
# Files to ignore completely
ignore_files = [
"src/legacy.py",
"src/experimental.py"
]
# Directories to exclude
exclude_dirs = [
".venv",
"node_modules",
".git"
]
# Functions/classes to ignore
ignore_names = [
"test_*", # Test functions
"setUp", # Test methods
"tearDown",
"main", # Entry points
]
# Ignore decorators
ignore_decorators = [
"app.route",
"pytest.fixture",
"property",
"staticmethod",
"classmethod",
"abstractmethod"
]
# Minimum number of references to consider "used"
min_references = 1
# Show unreachable code (after return/raise)
show_unreachable = false
Common Patterns
Unused Code Detection
# FOUND: Unused function
def unused_function():
return 42
# FOUND: Unused class
class UnusedClass:
pass
# FOUND: Unused variable
UNUSED_CONSTANT = 42
# FOUND: Unused import
import unused_module
Unreachable Code Detection
def example():
return 42
print("Unreachable") # FOUND: Code after return
def example2():
raise ValueError("Error")
cleanup() # FOUND: Code after raise
def example3():
if True:
return
else:
process() # FOUND: Unreachable branch
False Positives (Configuration)
# 1. Public API (keep even if unused internally)
# Add to ignore_names in pyproject.toml
[tool.deadcode]
ignore_names = ["PublicAPIClass", "public_function"]
# 2. Framework magic
[tool.deadcode]
ignore_decorators = ["app.route", "celery.task"]
# 3. Test infrastructure
[tool.deadcode]
ignore_names = ["test_*", "setUp*", "tearDown*"]
# 4. Entry points
[tool.deadcode]
ignore_names = ["main", "__main__"]
Comparison: Vulture vs deadcode
When to Choose Vulture
Use Vulture for:
- Large, mature codebases with complex dynamics
- Gradual cleanup with confidence-based filtering
- Whitelisting false positives easily
- Handling dynamic code (getattr, exec, etc.)
Example workflow:
# Start with high confidence
vulture --min-confidence 90 .
# Generate whitelist for false positives
vulture --make-whitelist > vulture_whitelist.py
# Edit whitelist manually
vim vulture_whitelist.py
# Run with whitelist
vulture . vulture_whitelist.py
When to Choose deadcode
Use deadcode for:
- New projects with strict code hygiene
- Fewer false positives desired
- AST-based accuracy
- Unreachable code detection
Example workflow:
# Generate initial config
deadcode --init
# Configure in pyproject.toml
[tool.deadcode]
paths = ["src"]
ignore_decorators = ["app.route"]
# Run checks
deadcode .
# Enforce in CI
deadcode --strict .
Hybrid Approach
Use both tools for comprehensive detection:
# Run vulture for broad detection
vulture --min-confidence 80 .
# Run deadcode for precise detection
deadcode .
# Compare results and whitelist false positives
CI Integration
GitHub Actions with Vulture
# .github/workflows/deadcode.yml
name: Dead Code Check
on: [push, pull_request]
jobs:
vulture:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
- name: Set up Python
run: uv python install 3.12
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Run vulture
run: |
uv run vulture . \
--min-confidence 80 \
vulture_whitelist.py
- name: Upload results
uses: actions/upload-artifact@v4
if: failure()
with:
name: vulture-results
path: vulture-output.txt
GitHub Actions with deadcode
# .github/workflows/deadcode.yml
name: Dead Code Check
on: [push, pull_request]
jobs:
deadcode:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
- name: Set up Python
run: uv python install 3.12
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Run deadcode
run: uv run deadcode .
- name: Check for unreachable code
run: uv run deadcode --show-unreachable .
Pre-commit Hook
# .pre-commit-config.yaml
repos:
# Vulture
- repo: https://github.com/jendrikseipp/vulture
rev: v2.11
hooks:
- id: vulture
args: ['--min-confidence', '80']
files: ^src/
# deadcode
- repo: https://github.com/albertas/deadcode
rev: v2.0.0
hooks:
- id: deadcode
args: ['.']
files: ^src/
Best Practices
1. Start with High Confidence
# Begin with high confidence (fewer false positives)
vulture --min-confidence 90 .
# Gradually lower threshold
vulture --min-confidence 80 .
vulture --min-confidence 70 .
2. Use Whitelists for False Positives
# vulture_whitelist.py
# Document WHY each item is whitelisted
# Framework routes (Flask/Django)
@app.route('/api/endpoint')
def api_handler(): # Called by framework
pass
# Pytest fixtures
@pytest.fixture
def sample_data(): # Used by test functions
return [1, 2, 3]
# Plugin hooks
def on_load(): # Called by plugin system
pass
3. Integrate into Development Workflow
# Local development: Quick check
vulture src/ --min-confidence 90
# Pre-commit: Catch obvious issues
pre-commit run vulture --all-files
# CI: Strict enforcement
vulture . --min-confidence 80 vulture_whitelist.py
4. Review and Clean Regularly
# Weekly: Review dead code
vulture --make-whitelist > current_issues.txt
# Compare with last week
diff current_issues.txt last_week_issues.txt
# Clean up incrementally
git grep "def unused_function" | xargs -I {} git rm {}
5. Combine with Other Tools
# Dead code + unused imports
vulture . && ruff check --select F401 .
# Dead code + type checking
vulture . && basedpyright
# Dead code + coverage
pytest --cov=src && vulture src/
Common Pitfalls
1. Dynamic Code
# Problem: vulture can't detect dynamic usage
def dynamic_call():
pass
# Called via getattr
func = getattr(module, "dynamic_call")
func()
# Solution: Whitelist or use ignore comment
def dynamic_call(): # noqa: vulture
pass
2. Test Code
# Problem: Test fixtures appear unused
@pytest.fixture
def sample_data(): # Appears unused to vulture
return [1, 2, 3]
# Solution: Configure ignore_decorators
[tool.vulture]
ignore_decorators = ["pytest.fixture"]
3. Public API
# Problem: Public API unused internally
class PublicAPI:
def public_method(self): # Not called in codebase
pass
# Solution: Whitelist or document
[tool.deadcode]
ignore_names = ["PublicAPI"]
4. Framework Magic
# Problem: Framework calls code dynamically
class Meta: # Django ORM metadata
db_table = 'users'
@app.route('/api') # Flask route
def endpoint():
pass
# Solution: Configure ignore_decorators
[tool.vulture]
ignore_decorators = ["app.route"]
ignore_names = ["Meta"]
Integration with IDEs
VS Code
// settings.json
{
"python.linting.enabled": true,
"python.linting.vulture.enabled": true,
"python.linting.vulture.args": [
"--min-confidence", "80"
]
}
Neovim with LSP
-- Using null-ls
local null_ls = require("null-ls")
null_ls.setup({
sources = {
null_ls.builtins.diagnostics.vulture.with({
extra_args = { "--min-confidence", "80" }
}),
}
})
Summary
Vulture provides confidence-based dead code detection:
- Install:
uv add --dev vulture - Usage:
vulture --min-confidence 80 . - Whitelists:
vulture_whitelist.pyfor false positives - Best for: Large codebases, gradual cleanup
deadcode provides AST-based detection:
- Install:
uv add --dev deadcode - Usage:
deadcode . - Configuration:
pyproject.tomlwith[tool.deadcode] - Best for: New projects, strict enforcement
Best practices:
- Start with high confidence thresholds (90+)
- Use whitelists for legitimate false positives
- Integrate into CI for continuous monitoring
- Combine with other tools (ruff, basedpyright, coverage)
- Review and clean regularly
- Document WHY code is whitelisted
Hybrid approach:
- Use vulture for broad detection with confidence scores
- Use deadcode for precise detection with fewer false positives
- Compare results and maintain whitelists accordingly