pytest coverage exclude: omit files, folders and lines
The omit patterns and pragmas that work with pytest-cov 7.1 and coverage.py 7.17, and six that look right but are not.

Put file patterns in omit under [tool.coverage.run] and start them with a
wildcard: */generated/*. To leave out lines, add # pragma: no cover, and
add your own patterns with exclude_also, never exclude_lines.
Exclude patterns at a glance
| To exclude | Write |
|---|---|
| A folder anywhere | omit = ["*/generated/*"] |
| A folder from the project root | omit = ["src/shop/generated/*"] |
| A file by name, in any folder | omit = ["money.py"] |
| From the command line | coverage run --omit='*/generated/*' -m pytest |
| One line or block | # pragma: no cover on the line that opens it |
| Every line like a pattern | exclude_also = ["if __name__ == .__main__.:"] |
pytest-cov has no --omit flag. It reads the same configuration as
coverage.py: pyproject.toml, .coveragerc, setup.cfg or tox.ini.
We ran every setup here with pytest 9.2.0, pytest-cov 7.1.0 and coverage.py
7.17.2 on Python 3.13. The project has a shop package under src, with a
generated client and a legacy module no test imports. With --cov=shop and no
exclusions, the report has 17 of 21 statements (81%).
Omit files and folders
[tool.coverage.run]
omit = [
"*/generated/*",
"*/legacy/*",
]pytest --cov=shop
The report then had 14 of 15 statements (93%). src/shop/generated/* did the
same. A pattern that starts with a wildcard is used as is; any other pattern
is read from the folder you run pytest in.
Use --cov=shop, not a bare --cov. A bare --cov measured our test file
too, and left out the legacy module no test imports. --cov=shop reported
that module, at 0 of 2 statements, and no test files.
Exclude lines with pragma: no cover
def fmt(cents: int) -> str:
if cents < 0: # pragma: no cover
return "-" + fmt(-cents)
return f"{cents // 100}.{cents % 100:02d}"
The comment on the if excludes the whole branch under it. Coverage.py 7.17
also excludes if TYPE_CHECKING: blocks and ... stub bodies on its own.
To exclude every line of a kind, add a regular expression with
exclude_also:
[tool.coverage.report]
exclude_also = [
"if __name__ == .__main__.:",
]

Why your pytest coverage exclude isn’t working
| What we tried | What happened |
|---|---|
omit = ["generated/*"] | Nothing omitted: read from the run folder, not the package |
omit = ["src/shop/generated"] (no /*) | Nothing omitted |
omit = ["shop.generated.*"] (a module name) | Nothing omitted |
exclude_lines instead of exclude_also | # pragma: no cover and if TYPE_CHECKING: stopped working: 7 of 9 statements instead of 5 of 5 |
omit in pyproject.toml and a .coveragerc in the same folder | .coveragerc won; the pyproject.toml setting was ignored |
A bare --cov | Test files in the report, unimported modules missing |

exclude_lines replaces coverage.py’s default patterns, including the one for
# pragma: no cover. exclude_also adds to them. If you see exclude_lines
in an old answer, switch it.
omit also works under [tool.coverage.report]. There it hides files from
the report but still measures them, which looks the same in the report.
What Supercov adds
npx supercov -- pytest
npx supercov runs latest gaps
Supercov runs the same pytest command and records which test covered each
line, with branches and MC/DC. It decides what counts from your source
directories, not from omit. See
pytest-cov vs coverage.py for the two
ways to run coverage, and Python code coverage
for the tools side by side.