From 78d6633d32f04edd4c0cc93baea988fa05d75555 Mon Sep 17 00:00:00 2001 From: Max Isbey <224885523+maxisbey@users.noreply.github.com> Date: Fri, 16 Jan 2026 15:45:37 +0100 Subject: [PATCH] ci: add strict-no-cover to detect unnecessary coverage pragmas Add strict-no-cover from pydantic to CI pipeline. This tool identifies `# pragma: no cover` comments on lines that are actually covered by tests, helping keep coverage pragmas accurate. Changes: - Add strict-no-cover as dev dependency (installed from git) - Add `pragma: lax no cover` to coverage exclude_lines for partial coverage - Add CI step to run strict-no-cover after coverage report --- .github/workflows/shared.yml | 3 +++ pyproject.toml | 3 +++ uv.lock | 11 +++++++++++ 3 files changed, 17 insertions(+) diff --git a/.github/workflows/shared.yml b/.github/workflows/shared.yml index 3ace33a09c..c37311b2a3 100644 --- a/.github/workflows/shared.yml +++ b/.github/workflows/shared.yml @@ -62,6 +62,9 @@ jobs: uv run --frozen --no-sync coverage combine uv run --frozen --no-sync coverage report + - name: Check for unnecessary no cover pragmas + run: uv run --frozen --no-sync strict-no-cover + readme-snippets: runs-on: ubuntu-latest steps: diff --git a/pyproject.toml b/pyproject.toml index e1b175c769..0895a29247 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,6 +67,7 @@ dev = [ "dirty-equals>=0.9.0", "coverage[toml]>=7.13.1", "pillow>=12.0", + "strict-no-cover", ] docs = [ "mkdocs>=1.6.1", @@ -154,6 +155,7 @@ members = ["examples/clients/*", "examples/servers/*", "examples/snippets"] [tool.uv.sources] mcp = { workspace = true } +strict-no-cover = { git = "https://github.com/pydantic/strict-no-cover" } [tool.pytest.ini_options] log_cli = true @@ -207,6 +209,7 @@ ignore_errors = true precision = 2 exclude_lines = [ "pragma: no cover", + "pragma: lax no cover", "if TYPE_CHECKING:", "@overload", "raise NotImplementedError", diff --git a/uv.lock b/uv.lock index d2a5158630..70f2d0e4f7 100644 --- a/uv.lock +++ b/uv.lock @@ -764,6 +764,7 @@ dev = [ { name = "pytest-pretty" }, { name = "pytest-xdist" }, { name = "ruff" }, + { name = "strict-no-cover" }, { name = "trio" }, ] docs = [ @@ -811,6 +812,7 @@ dev = [ { name = "pytest-pretty", specifier = ">=1.2.0" }, { name = "pytest-xdist", specifier = ">=3.6.1" }, { name = "ruff", specifier = ">=0.8.5" }, + { name = "strict-no-cover", git = "https://github.com/pydantic/strict-no-cover" }, { name = "trio", specifier = ">=0.26.2" }, ] docs = [ @@ -2533,6 +2535,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/51/da/545b75d420bb23b5d494b0517757b351963e974e79933f01e05c929f20a6/starlette-0.49.1-py3-none-any.whl", hash = "sha256:d92ce9f07e4a3caa3ac13a79523bd18e3bc0042bb8ff2d759a8e7dd0e1859875", size = 74175, upload-time = "2025-10-28T17:34:09.13Z" }, ] +[[package]] +name = "strict-no-cover" +version = "0.1.1" +source = { git = "https://github.com/pydantic/strict-no-cover#7fc59da2c4dff919db2095a0f0e47101b657131d" } +dependencies = [ + { name = "pydantic", version = "2.11.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14'" }, + { name = "pydantic", version = "2.12.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" }, +] + [[package]] name = "tomli" version = "2.2.1"