DEV Community

Sour durian
Sour durian

Posted on

Python Dead Code: I Scanned Flask, FastAPI, and 7 Other Popular Repos — Here's What I Found

Dead code is the tech debt nobody talks about. Unused functions, orphaned imports, abandoned classes — they get maintained, reviewed in PRs, and tested in CI. And they do absolutely nothing.

I wanted to answer two questions:

  1. How much dead code exists in the most popular Python projects on GitHub?
  2. Can static analysis tools reliably detect it without drowning you in false positives?

So I ran dead code detection on 9 of the most popular Python repositories (350k+ combined stars) and manually verified every single finding.

The 9 Python Repos I Tested

Repository Stars Why it's a good stress test
fastapi/fastapi 82k 100+ Pydantic model fields for OpenAPI specs
pallets/flask 69k Jinja2 template globals, Werkzeug protocol methods
psf/requests 53k Heavy __init__.py re-exports
Textualize/rich 51k __rich_console__ protocol, metaclasses
tqdm/tqdm 30k Keras/Dask callbacks, pandas monkey-patching
pydantic/pydantic 23k Mypy plugin hooks, __getattr__ dynamic config
pallets/click 17k IO protocol methods, nonlocal closures
encode/httpx 14k Transport/auth protocol methods — zero dead code
encode/starlette 10k ASGI interface params, polymorphic dispatch

Every finding was manually verified against the source code. No automated labelling. No cherry-picking.

How Much Dead Code Did I Find?

Across all 9 repos: 52 genuinely dead items — unused functions, classes, imports, and variables.

But here's the interesting part: the false positive problem is way worse than the dead code itself.

I compared two Python dead code detection tools — Vulture (the most popular Python dead code finder) and Skylos (a framework-aware tool I built to reduce false positives).

Python Dead Code Detection: Skylos vs Vulture

Repository Dead Items Skylos Found Skylos FP Vulture Found Vulture FP
psf/requests 6 6 35 6 58
pallets/click 7 7 8 6 6
encode/starlette 1 1 4 1 2
Textualize/rich 13 13 14 10 8
encode/httpx 0 0 6 0 59
pallets/flask 7 7 12 6 260
pydantic/pydantic 11 11 93 10 112
fastapi/fastapi 6 6 30 4 102
tqdm/tqdm 1 0 18 1 37
Total 52 51 220 44 644

Summary

Metric Skylos Vulture
Recall 98.1% (51/52) 84.6% (44/52)
False Positives 220 644
Dead items found 51 44

Skylos finds 7 more dead items with 3x fewer false positives.

Why Python Dead Code Detection Produces So Many False Positives

The biggest source of noise? Python framework magic. Django, Flask, FastAPI, and pytest all use patterns that look like dead code to static analysis but are very much alive at runtime.

Flask: 260 False Positives from Vulture

# Vulture flags this as unused — but Jinja2 calls it at render time
@app.template_global()
def format_date(dt):
    return dt.strftime("%Y-%m-%d")
Enter fullscreen mode Exit fullscreen mode

Vulture reported 260 false positives on Flask. Most were Jinja2 template globals and Werkzeug protocol methods that Flask calls internally. Skylos reported 12 because it recognizes Flask-specific patterns.

FastAPI: Pydantic Model Fields Aren't Unused Variables

class ValidationError(BaseModel):
    detail: str
    status_code: int = 422  # Vulture: "unused variable"
    headers: dict | None = None  # Vulture: "unused variable"
Enter fullscreen mode Exit fullscreen mode

Pydantic BaseModel fields define your API schema. They're serialized, validated, and documented by OpenAPI — but never "called" in the traditional sense. Vulture flagged 102 of these in FastAPI. Skylos flagged 30.

Where Skylos Still Gets It Wrong (Honestly)

No Python dead code tool is perfect. Some patterns still fool Skylos:

Repo Skylos FP Vulture FP Why Skylos loses
click 8 6 IO protocol methods on io.RawIOBase subclasses
starlette 4 2 Instance method calls not resolved to class definitions
rich 14 8 Sentinel vars checked via f_locals.get("name")

When code uses very dynamic Python patterns like frame inspection (f_locals), both tools struggle. Vulture actually does better on rich because its more conservative analysis happens to avoid those specific cases.

The Python Repo with Zero Dead Code

httpx had zero dead items. Every function, class, and import is used. It's one of the cleanest Python codebases I've seen.

But Vulture still reported 59 false positives on it — mostly transport and auth protocol methods that implement interfaces without explicit callers in the same codebase. Skylos reported 6.

A tool that reports 59 issues when there are 0 real problems trains developers to ignore its output entirely.

What Dead Code I Actually Found in Popular Python Projects

Some highlights from genuinely dead code:

  • requests: 6 dead items including unused re-exports in __init__.py that survived years of refactoring
  • rich: 13 dead items — unused utility functions and classes that were replaced but never removed
  • pydantic: 11 dead items including leftover mypy plugin hooks from API changes
  • flask: 7 dead items — old extension hooks that nothing calls anymore

None of these are security vulnerabilities. But they add up: dead code gets reviewed in PRs, confuses new contributors, and creates false dependencies that make refactoring harder.

How to Find Dead Code in Your Own Python Project

All benchmark scripts and ground truth data are open source:

git clone https://github.com/duriantaco/skylos-demo
cd skylos-demo

# Run any individual benchmark
cd real_life_examples/flask
python3 ../benchmark_flask.py

# Or install and try on your own project
pip install skylos
skylos your-project/
Enter fullscreen mode Exit fullscreen mode

Skylos also does security scanning (taint analysis, hardcoded secrets, SQL injection) and has an AI remediation agent that can auto-fix issues and open PRs.

Full methodology, ground truth lists, and per-repo breakdowns: skylos-demo

Key Takeaways

  1. Dead code exists everywhere — even in the most popular, well-maintained Python projects
  2. False positives are the real problem — a tool that reports 644 issues when only 52 are real trains you to ignore static analysis entirely
  3. Framework awareness matters for Python — Django views, FastAPI endpoints, Pydantic fields, pytest fixtures — if your dead code tool doesn't understand Python frameworks, most of its output is noise
  4. Zero dead code is achievable — httpx proves it. Clean Python codebases exist.

What does your project's dead code situation look like? Try running pip install skylos && skylos . and let me know in the comments.

Top comments (0)