pytest-cov Reports 0% / "module-not-imported" - No Source Measured
pytest-cov ran but measured no real code, reporting 0% or warning that modules were never imported. The --cov target points at a path that is not the imported package, so coverage watches files that never load.
What this error means
Coverage prints 0% for your package, or CoverageWarning: Module X was never imported / No data was collected. Tests pass, but the report is empty because the measured path and the imported path differ (often a src-layout or installed-package mismatch).
CoverageWarning: Module myapp was never imported. (module-not-imported)
CoverageWarning: No data was collected. (no-data-collected)
TOTAL 0 0 0%Diagnose it: what did pytest actually collect?
Most pytest failures that only happen in CI are collection or import-path problems rather than test failures. The runner has a different working directory, a different sys.path, and usually no editable install, so a test module that imports your package locally may not resolve at all.
# what would run, without running it
pytest --collect-only -q | tail -20
# where pytest thinks the root is (drives conftest and import mode)
pytest --collect-only 2>&1 | grep -i rootdir
# is the package importable at all from the runner cwd?
python -c "import yourpackage, sys; print(yourpackage.__file__)"
python -c "import sys; print(sys.path)"Common causes
--cov points at the wrong path
Passing --cov=src or a directory that is not the importable package name means coverage instruments files that tests never import, so nothing is recorded.
Installed package measured instead of source (or vice versa)
With a src-layout and an installed/editable package, tests import from site-packages while --cov watches the source tree (or the reverse), so the imported module is not the measured one.
How to fix it
Point --cov at the import package name
Measure by the importable package name so coverage tracks the modules tests actually load.
pytest --cov=myapp --cov-report=term-missing
# not --cov=src (a directory) unless that is the import nameConfigure source and path mapping for src-layout
Tell coverage the source root and map installed paths back to source so measurement and imports line up.
[tool.coverage.run]
source = ["myapp"]
[tool.coverage.paths]
source = ["src/myapp", "*/site-packages/myapp"]Make a zero-test run fail the build
# fail explicitly when nothing is collected
pytest --strict-markers -q
test "${PIPESTATUS[0]}" -ne 5 || { echo "pytest collected no tests"; exit 1; }How to prevent it
- Use the import package name for
--cov, not a directory. - Configure
[tool.coverage.paths]for src-layout/installed packages. - Fail the build on coverage warnings to catch a zero-measurement run early.