The Hidden Cost of Dead Code
Dead code isn’t just clutter. It’s active technical debt that:Slows Development
Developers read and reason about code that does nothing
Hides Bugs
Unused code paths can mask logic errors and security issues
Increases Attack Surface
Vulnerable code that’s “not used” can still be exploited
Bloats Bundles
Unused imports increase load times and memory usage
How Skylos Finds Dead Code
Skylos builds a complete reference graph of your codebase, then identifies definitions with zero references.What Gets Detected
| Category | Example | Detection Method |
|---|---|---|
| Unreachable functions | def helper(): ... never called | No call references found |
| Unused imports | import json but json never used | No name references found |
| Unused classes | class OldModel: ... never instantiated | No instantiation or inheritance |
| Unused variables | result = compute() but result never read | Assigned but never referenced |
| Unused parameters | def fn(a, b): return a | Parameter b never used in body |
The Confidence System
Not all “unused” code is actually dead. A helper function might be:- Called dynamically via
getattr() - Used by a framework implicitly
- Part of a public API
Confidence Penalties
| Pattern | Penalty | Reason |
|---|---|---|
Private name (_foo) | -80 | Convention for internal use |
Dunder (__str__) | -100 | Called implicitly by Python |
Underscore var (_) | -100 | Intentionally unused |
In __init__.py | -15 | Often public API re-exports |
| Framework decorator | -40 | Called by framework |
| Dynamic module | -40 | May use getattr() |
| Test-related | -100 | Called by test runner |
Using Confidence Threshold
Framework Awareness
Skylos understands that framework code is called implicitly:- Django
- Flask / FastAPI
- Pydantic
- Pytest
Smart Tracing (Runtime Analysis)
Static analysis can’t catch everything. When code is called dynamically viagetattr(), visitor patterns, or reflection, Skylos may flag it as unused.
The solution: Run your tests with call tracing enabled.
- Runs your test suite with
sys.settrace()enabled - Records every function that was actually called
- Uses that data to eliminate false positives
What Gets Captured
| Pattern | Static Analysis | With --trace |
|---|---|---|
visitor.visit(node) → visit_FunctionDef() | ❌ Missed | ✅ Caught |
getattr(obj, "method")() | ❌ Missed | ✅ Caught |
Plugin hooks (pytest_configure) | ❌ Missed | ✅ Caught |
| Reflection / dynamic imports | ❌ Missed | ✅ Caught |
When to Use --trace
- Use It
- Skip It
- Projects with visitor patterns (AST, CST)
- Plugin architectures
- Heavy use of
getattr()/ reflection - Many false positives from static analysis
How It Works
Tip: Commit
.skylos_trace to your repo if your test suite is stable. Then skylos . will use it automatically without re-running tests.Comparison: Why Not Just Use Your IDE?
| Feature | IDE “Unused” Warning | Skylos |
|---|---|---|
| Cross-file analysis | ❌ Single file | ✅ Entire codebase |
| Framework awareness | ❌ | ✅ Django, Flask, FastAPI, Pydantic |
| Confidence scoring | ❌ | ✅ Filter uncertain findings |
| CI/CD integration | ❌ | ✅ Block PRs, generate reports |
| Batch removal | ❌ | ✅ Interactive selection |
| Import tracking | Basic | ✅ Resolves re-exports |
Safe Removal Workflow
1
Scan with high confidence
Start with findings you can trust:
2
Review in interactive mode
Select what to remove:
3
Remove or comment out
4
Run tests
Verify nothing broke:
Comment-Out Mode
Instead of deleting, Skylos can comment out code with a marker:SKYLOS DEADCODE later to permanently remove or restore.
Output Formats
- Table (Default)
- Tree
- JSON
Real-World Impact
Case Study: E-commerce Platform
A 200K LOC Python codebase ran Skylos and found:
- 47 unused functions (3,200 lines of dead code)
- 156 unused imports (faster startup, smaller bundles)
- 12 unused classes (legacy models never migrated)
