coverage.py: measuring which Python lines actually run
The code coverage tool for Python. It uses the code analysis tools and tracing hooks provided in the Python standard library to determine which lines are executable, and which have been executed.
At a glance
- What is it?
- coverage.py is the Python code coverage tool that uses the standard library's tracing hooks to record executed lines and branches. It is the engine most Python test suites sit on, and it is best judged by what it measures and what it deliberately does not.
- Who is it for?
- Adopt coverage.py when you want line and branch execution data from the tracing hooks in the Python standard library, and when a plain coverage report is enough to find untested paths. Do not adopt it if you need static analysis of code that never runs, or a single dashboard that also tracks bugs and quality gates.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What coverage.py measures, and the question it answers
Coverage.py answers one question: which parts of a Python program were executed. The README describes the mechanism plainly. It uses the code analysis tools and tracing hooks provided in the Python standard library to determine which lines are executable, and which have been executed. That distinction matters. The tool first decides what counts as an executable line, then records whether execution reached it.
The audience is anyone running a Python test suite who wants to know what the tests missed. That includes library maintainers checking a new code path, application teams gating a pull request, and anyone who has ever deleted a branch and wondered whether a test still covers the replacement. The typical entry point is running it around an existing test command rather than writing new tests.
It is not a linter and not a static analyzer. It reports on execution, so code that never runs during the measured session is invisible to it by construction. That is the whole design, not a gap in it.
Tracing hooks, the data file, and the run/report split
The architecture follows from the README's description: coverage.py installs tracing hooks from the standard library, watches execution, and writes what it saw to a data file. Reporting is a separate step that reads that file. The split is the part worth understanding before you wire anything into CI, because the run and the report can happen in different processes, on different machines, or hours apart.
Because analysis and execution are separated, the executable-line determination happens through code analysis rather than through a single pass of the interpreter. The project's own repository reflects that structure: there is a coverage/ package, a tests/ directory, and a metacov.ini at the top level, which suggests the project measures its own coverage with the same tool. The repository also carries a quality workflow separate from the test suite workflow, so static checks and execution checks are not the same job.
Supported interpreters are stated in the README: Python 3.10 through 3.15 rc1, including free-threading, plus PyPy3 versions 3.10 and 3.11. If you are on an older Python, the README does not claim support for it.
Installing coverage.py and running it for the first time
The README points new users at the Quick Start section of the documentation on Read the Docs, which is where the exact commands live. The package is published on PyPI under the name coverage, the target of the README's PyPI badge, so the install step is a normal pip install of that distribution name.
The documented flow is two steps. First you run your program or test suite under the coverage command so the tracing hooks record execution into a data file. Then you run a report step that reads that data file and prints results. The README does not reproduce those commands inline; it links to the Quick Start section, so copy the flags from there rather than guessing them.
What you should expect from the split is that the first step prints no report. If you run only the first step and see no numbers, nothing is broken. The report step is what turns the recorded execution into per-file figures. For a browsable rather than tabular view, the documentation also describes HTML output; check the Quick Start section for the exact option and output location.
Where coverage.py is the wrong tool
The clearest limitation is built into the measurement method. Coverage.py records what executed. A function with a bug on a branch that no test ever reaches will show as uncovered, which is useful, but a line that executes and produces the wrong result still counts as covered. High coverage numbers and correct behaviour are different properties, and the tool only reports the first.
There is also a cost to tracing. Every executed line passes through a hook, so a coverage run is slower than the same suite without it. The README does not publish a slowdown figure, and the project does not present itself as a profiler, so treat the overhead as a real but unquantified cost in the documentation.
Finally, the run and report split creates an operational failure mode. If the data file is lost between steps, or if the report step runs against stale data from a previous invocation, the numbers you see describe a different execution than the one you think you measured. That is a workflow problem rather than a defect, but it is the one that most often produces misleading reports.
coverage.py compared with pytest-cov
The practical alternative most Python developers weigh is pytest-cov, the pytest plugin. The difference is in who owns the workflow. Coverage.py is a standalone command with its own run and report steps, usable against any program, not only tests, and not only pytest. pytest-cov wraps coverage.py inside the pytest process, so a single pytest invocation both runs the tests and produces coverage output.
That convenience has a boundary. Because pytest-cov drives coverage.py, the underlying measurement and the supported Python versions come from coverage.py itself. What changes is the invocation and the configuration surface: plugin options versus coverage.py's own configuration and command line. If your test runner is not pytest, the plugin does not apply and the standalone commands are the path. If your suite is pytest-only and you want one command, the plugin removes a step.
The other comparison that appears in search data is SonarQube. SonarQube is a broader code quality platform, not a coverage measurement library, so it is not a substitute for what coverage.py does. The two can coexist: coverage.py produces the execution data, and a platform consumes a report format. That is a pipeline decision, not either/or.
Maintenance cost, releases, and the licence
The repository is not archived, and the last push was on 2026-08-28. Recent releases follow closely: 7.16.0 on 2026-08-28, 7.15.4 on 2026-08-06, and 7.15.3 on 2026-08-02. That cadence means upgrades arrive often enough that pinning a version in a requirements file is worth doing, and the change history page linked from the README is where to check what moved between them.
The README states the supported interpreters explicitly, which sets the upgrade cost: Python 3.10 through 3.15 rc1, including free-threading, and PyPy3 versions 3.10 and 3.11. If you run an interpreter outside that list, you are outside what the project documents, and the README does not describe a fallback.
Licensing is Apache-2.0, per both the README and LICENSE.txt in the repository, with details in NOTICE.txt. Apache-2.0 is a permissive licence that permits commercial use, but this is a summary of what the repository states, not legal advice. If you redistribute coverage.py or a modified version, read NOTICE.txt and consult your own counsel about attribution requirements.
Editorial conclusion
Adopt coverage.py when you want line and branch execution data from the tracing hooks in the Python standard library, and when a plain coverage report is enough to find untested paths. Do not adopt it if you need static analysis of code that never runs, or a single dashboard that also tracks bugs and quality gates. Before wiring it into CI, check the Python versions it supports against your interpreter, read the Quick Start section of the docs for the exact run and report commands, and confirm how you will store the data file between the run and the report steps.
Frequently asked questions
How do I use the coverage run command with pytest?
Run the test module under coverage's run command, then read the data with the report command. The run step writes the data file and prints nothing; the report step is what shows the per-file numbers.
What is coverage.py?
It is a code coverage measurement tool for Python. The README states that it uses the code analysis tools and tracing hooks in the Python standard library to determine which lines are executable and which have been executed.
How do I install coverage.py?
It is published on PyPI under the name coverage, so a normal pip install brings it in. The README's Quick Start section of the docs covers running it against a test suite.
How do I use coverage.py?
The documented flow is to run your program or test suite under the coverage run command, which records execution to a data file, and then run a report step against that file. The README directs new users to the Quick Start section of coverage.readthedocs.io.
What is the difference between coverage.py and pytest-cov?
Coverage.py is the standalone measurement tool with separate run and report commands, usable against any program. pytest-cov is a pytest plugin that drives coverage.py inside the pytest process, so one pytest invocation produces the coverage output.
What is code coverage?
Coverage.py's README frames it as determining which lines are executable and which have been executed. The number reflects execution, not whether the executed code behaved correctly.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/coveragepy-coveragepy)