ci: run strict-no-cover in scripts/test to catch stale pragmas locally (#2305)
This commit is contained in:
@@ -29,18 +29,31 @@ This document contains critical information about working with this codebase. Fo
|
||||
- IMPORTANT: The `tests/client/test_client.py` is the most well designed test file. Follow its patterns.
|
||||
- IMPORTANT: Be minimal, and focus on E2E tests: Use the `mcp.client.Client` whenever possible.
|
||||
- Coverage: CI requires 100% (`fail_under = 100`, `branch = true`).
|
||||
- Full check: `./scripts/test` (~20s, matches CI exactly)
|
||||
- Targeted check while iterating:
|
||||
- Full check: `./scripts/test` (~23s). Runs coverage + `strict-no-cover` on the
|
||||
default Python. Not identical to CI: CI also runs 3.10–3.14 × {ubuntu, windows},
|
||||
and some branch-coverage quirks only surface on specific matrix entries.
|
||||
- Targeted check while iterating (~4s, deterministic):
|
||||
|
||||
```bash
|
||||
uv run --frozen coverage erase
|
||||
uv run --frozen coverage run -m pytest tests/path/test_foo.py
|
||||
uv run --frozen coverage combine
|
||||
uv run --frozen coverage report --include='src/mcp/path/foo.py' --fail-under=0
|
||||
UV_FROZEN=1 uv run --frozen strict-no-cover
|
||||
```
|
||||
|
||||
Partial runs can't hit 100% (coverage tracks `tests/` too), so `--fail-under=0`
|
||||
and `--include` scope the report to what you actually changed.
|
||||
and `--include` scope the report. `strict-no-cover` has no false positives on
|
||||
partial runs — if your new test executes a line marked `# pragma: no cover`,
|
||||
even a single-file run catches it.
|
||||
- Coverage pragmas:
|
||||
- `# pragma: no cover` — line is never executed. CI's `strict-no-cover` fails if
|
||||
it IS executed. When your test starts covering such a line, remove the pragma.
|
||||
- `# pragma: lax no cover` — excluded from coverage but not checked by
|
||||
`strict-no-cover`. Use for lines covered on some platforms/versions but not
|
||||
others.
|
||||
- `# pragma: no branch` — excludes branch arcs only. coverage.py misreports the
|
||||
`->exit` arc for nested `async with` on Python 3.11+ (worse on 3.14/Windows).
|
||||
- Avoid `anyio.sleep()` with a fixed duration to wait for async operations. Instead:
|
||||
- Use `anyio.Event` — set it in the callback/handler, `await event.wait()` in the test
|
||||
- For stream messages, use `await stream.receive()` instead of `sleep()` + `receive_nowait()`
|
||||
|
||||
@@ -6,3 +6,6 @@ uv run --frozen coverage erase
|
||||
uv run --frozen coverage run -m pytest -n auto $@
|
||||
uv run --frozen coverage combine
|
||||
uv run --frozen coverage report
|
||||
# strict-no-cover spawns `uv run coverage json` internally without --frozen;
|
||||
# UV_FROZEN=1 propagates to that subprocess so it doesn't touch uv.lock.
|
||||
UV_FROZEN=1 uv run --frozen strict-no-cover
|
||||
|
||||
Reference in New Issue
Block a user