From 6945cdef0aed7147304f4d30b25b42fcedb20b12 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Tue, 10 Sep 2024 02:01:23 +0200 Subject: [PATCH] Add coverage reporting to the test suite - the nox session "test-coverage" triggers further nox sessions that run the test suite for all supported Python versions - the nox session "_test-coverage-run" runs the test suite for a particular Python version using the coverage tool - the nox session "_test-coverage-report" combines the individual coverage reports --- .gitignore | 1 + noxfile.py | 86 +++++++++++++++++++++++++++++++++++++++++++++----- poetry.lock | 2 +- pyproject.toml | 1 + 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 13eb353..c22ea0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .cache/ +dist/ poetry.toml **/__pycache__/ .venv/ diff --git a/noxfile.py b/noxfile.py index 8751332..301aa2e 100644 --- a/noxfile.py +++ b/noxfile.py @@ -2,6 +2,7 @@ import collections import pathlib +import random import re import tempfile from collections.abc import Mapping @@ -145,20 +146,22 @@ def lint(session: nox.Session) -> None: session.run("ruff", "check", *locations) +TEST_DEPENDENCIES = ( + "packaging", + "pytest", + "pytest-cov", + "semver", + "xdoctest", +) + + @nox_session(python=SUPPORTED_PYTHONS) def test(session: nox.Session) -> None: """Test code with `pytest`.""" start(session) install_unpinned(session, "-e", ".") # "-e" makes session reuseable - install_pinned( - session, - "packaging", - "pytest", - "pytest-cov", - "semver", - "xdoctest", - ) + install_pinned(session, *TEST_DEPENDENCIES) args = session.posargs or ( "--cov", @@ -169,6 +172,58 @@ def test(session: nox.Session) -> None: session.run("pytest", *args) +_magic_number = random.randint(0, 987654321) # noqa: S311 + + +@nox_session(name="test-coverage", python=MAIN_PYTHON, reuse_venv=True) +def test_coverage(session: nox.Session) -> None: + """Report the combined coverage statistics. + + Run the test suite for all supported Python versions + and combine the coverage statistics. + """ + install_pinned(session, "coverage") + + session.run("python", "-m", "coverage", "erase") + + for version in SUPPORTED_PYTHONS: + session.notify(f"_test-coverage-run-{version}", (_magic_number,)) + session.notify("_test-coverage-report", (_magic_number,)) + + +@nox_session(name="_test-coverage-run", python=SUPPORTED_PYTHONS, reuse_venv=False) +def test_coverage_run(session: nox.Session) -> None: + """Measure the test coverage.""" + do_not_reuse(session) + do_not_run_directly(session) + + start(session) + + session.install(".") + install_pinned(session, "coverage", *TEST_DEPENDENCIES) + + session.run( + "python", + "-m", + "coverage", + "run", + "-m", + "pytest", + TESTS_LOCATION, + ) + + +@nox_session(name="_test-coverage-report", python=MAIN_PYTHON, reuse_venv=True) +def test_coverage_report(session: nox.Session) -> None: + """Report the combined coverage statistics.""" + do_not_run_directly(session) + + install_pinned(session, "coverage") + + session.run("python", "-m", "coverage", "combine") + session.run("python", "-m", "coverage", "report", "--fail-under=100") + + @nox_session(name="test-docstrings", python=MAIN_PYTHON) def test_docstrings(session: nox.Session) -> None: """Test docstrings with `xdoctest`.""" @@ -179,6 +234,21 @@ def test_docstrings(session: nox.Session) -> None: session.run("xdoctest", "src/lalib") +def do_not_reuse(session: nox.Session, *, raise_error: bool = True) -> None: + """Do not reuse a session with the "-r" flag.""" + if session._runner.venv._reused: # noqa:SLF001 + if raise_error: + session.error('The session must be run without the "-r" flag') + else: + session.warn('The session must be run without the "-r" flag') + + +def do_not_run_directly(session: nox.Session) -> None: + """Do not run a session with `nox -s SESSION_NAME` directly.""" + if not session.posargs or session.posargs[0] != _magic_number: + session.error("This session must not be run directly") + + def start(session: nox.Session) -> None: """Show generic info about a session.""" if session.posargs: diff --git a/poetry.lock b/poetry.lock index 6438f42..f39a1f3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1048,4 +1048,4 @@ tests-strict = ["pytest (==4.6.0)", "pytest (==6.2.5)", "pytest-cov (==3.0.0)"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "3648b3426753e3e36e575d6b08fe8ab1b5f5443dcf2d1effaed5e921cdb40933" +content-hash = "41aa1b0224786397f339cd01099c1a687cb57e16898426ef101fd66247d3bd5c" diff --git a/pyproject.toml b/pyproject.toml index 477f59e..9363e64 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,6 +60,7 @@ pydoclint = { extras = ["flake8"], version = "^0.5" } ruff = "^0.6" # Test suite +coverage = "^7.6" packaging = "^24.1" # to test the version identifier pytest = "^8.3" pytest-cov = "^5.0"