Skip to main content

Live code coverage for a running Flask application.

Project description

flask-coverage

Live code coverage for a running Flask application.

flask-coverage wraps coverage.py as a Flask extension and exposes a small debug blueprint at /debug/coverage. You can introspect what's been executed so far, take snapshots, view a per-file HTML report, and export the raw .coverage data — all from a running process, without restarting it.

It is designed for two scenarios:

  • Browser tests. Run your full Flask app under Playwright/Selenium/Cypress, drive it however you like, then read the live coverage report to see which paths your end-to-end tests actually reach.
  • Production / canary. Measure what code your live traffic exercises. Coverage measurement carries some overhead (typically <15% on Python 3.12+ with sys.monitoring), but for low-to-mid QPS services that's a reasonable trade for ground-truth dead-code detection.

Install

pip install flask-coverage

Requires Python ≥ 3.12, Flask ≥ 2.3, coverage ≥ 7.4.

Quickstart

from flask import Flask
from flask_coverage import FlaskCoverage

app = Flask(__name__)
FlaskCoverage(app)   # mounts /debug/coverage

Run your app and visit http://127.0.0.1:5000/debug/coverage/.

A runnable demo with a step-by-step walkthrough lives in examples/.

Endpoints

Mounted under /debug/coverage by default (override with FlaskCoverage(app, url_prefix="…")).

Method Path Purpose
GET / Dashboard with text report and links to the others
GET /report Text report (same format as coverage report)
GET /html/ Native coverage.py HTML report (per-file source + line highlighting)
GET /files JSON list of measured files: {file, statements, missing, covered, percent}
POST /snapshot Flush in-memory counters to disk; returns JSON stats
GET /export Download the merged .coverage data file
POST /reset Erase all collected data

Configuration

Coverage settings are read from [tool.coverage.*] in pyproject.toml automatically (via coverage.py's native config support), or from .coveragerc / setup.cfg / tox.ini if present.

[tool.coverage.run]
source = ["myapp"]
parallel = true        # recommended for gunicorn/uwsgi (see Multi-worker)

[tool.coverage.report]
omit = ["*/migrations/*", "*/tests/*"]

Starting coverage early

For accurate measurement of module-level code, coverage must start before your application modules are imported. Three options, in order of preference:

  1. COVERAGE_PROCESS_START env var (best for gunicorn/uwsgi):

    export COVERAGE_PROCESS_START=$(pwd)/pyproject.toml
    gunicorn myapp:app
    
  2. flask-coverage CLI shim:

    flask-coverage --app myapp run --debug
    
  3. Manual start_early() as the very first line in wsgi.py:

    from flask_coverage import start_early
    start_early()                    # before any of your app modules
    from myapp import create_app
    app = create_app()
    

If a Coverage instance is already running (any of the above, or pytest-cov in tests), FlaskCoverage(app) adopts it instead of creating a duplicate tracer.

Security

The /debug/coverage blueprint exposes filesystem paths for every measured source file — treat it as sensitive. Registration is fail-closed: it requires one of the following, or it raises RuntimeError:

  • app.debug is True, or

  • FLASK_COVERAGE_PASSWORD env var is set (HTTP Basic auth — user admin, override with FLASK_COVERAGE_USERNAME), or

  • a custom auth= callback is passed to FlaskCoverage(...):

    FlaskCoverage(app, auth=lambda: current_user.is_authenticated and current_user.is_admin)
    

The basic-auth check uses hmac.compare_digest for constant-time comparison.

Operations

Disabling without redeploy

Set FLASK_COVERAGE_DISABLED to a truthy value (1, true, yes, on) before the process starts, and FlaskCoverage(app) becomes a no-op: no tracer, no blueprint, no auth check.

FLASK_COVERAGE_DISABLED=1 gunicorn myapp:app

Multi-worker (gunicorn / uwsgi)

Each worker traces independently. Set parallel = true under [tool.coverage.run] so each worker writes .coverage.<host>.<pid>.<rand>. The /report, /files, /html/, and /export endpoints automatically merge sibling files into a temporary copy before generating output, so a request served by any worker sees coverage from all of them.

The merge is non-destructive: original per-worker files on disk are never deleted, so workers keep accumulating data normally.

Performance

On Python 3.12+, coverage.py uses sys.monitoring (PEP 669), which is significantly faster than the legacy sys.settrace path — typically under 15% overhead. Acceptable for staging and canary; profile before turning on for high-QPS production traffic.

Development

git clone https://github.com/abilian/flask-coverage
cd flask-coverage
uv sync
uv run pytest          # 45 tests
make check             # lint + format + type check

Tests are organised by the test pyramid:

  • tests/a_unit/ — fast, isolated, mock-based
  • tests/b_integration/ — Flask test-client + mocked Coverage
  • tests/c_e2e/ — real coverage.Coverage running, including multi-worker simulation

CI runs ruff (lint + format), ty (type check), and pytest across Python 3.12 / 3.13 / 3.14.

License

MIT — see LICENSE.

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

flask_coverage-0.1.0.tar.gz (9.6 kB view details)

Uploaded Source

Built Distribution

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

flask_coverage-0.1.0-py3-none-any.whl (12.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: flask_coverage-0.1.0.tar.gz
  • Upload date:
  • Size: 9.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for flask_coverage-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3f62207ebfd4f6cde34943182f631adb1aae5fb72a04fcbe3817ed8b771b7e9a
MD5 dd7725e9e3dede61e0f2c8ff6fec5d16
BLAKE2b-256 4c9736636e0afa808dd12cc26be03bc59b735d4862e0f85e9289d1ee3a5bc725

See more details on using hashes here.

File details

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

File metadata

  • Download URL: flask_coverage-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for flask_coverage-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 83d5669f1ce4ecb1eccc427b1c7dcf84b52329138b50731d1f99b2acc87b8d63
MD5 831d49c464c7fba895d78b97aa024bc2
BLAKE2b-256 91e1046ecd5fc86d69c4eb8a99d74df47c432dc319663d782dd5135e10f7d031

See more details on using hashes here.

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