Skip to content

Reject pytest-xdist runs under --jamb instead of silently misreporting - #31

Merged
vanandrew merged 2 commits into
mainfrom
feat/xdist-guard
Jun 16, 2026
Merged

vanandrew merged 2 commits into
mainfrom
feat/xdist-guard

Conversation

@vanandrew

Copy link
Copy Markdown
Owner

What

When --jamb is combined with pytest-xdist (-n / --dist), jamb now fails fast with a clear usage error instead of producing a silently wrong traceability matrix.

Why

jamb accumulates test-to-requirement coverage on a single per-process RequirementCollector. Under xdist, tests run on worker processes; their outcomes are recorded there and never aggregated back to the controller, which is the process that generates the matrices and prints the summary. The result today is a distributed run that emits an incomplete or empty matrix with no warning.

For an IEC 62304 compliance artifact, a matrix that silently misreports test outcomes is worse than no matrix — so the right near-term behavior is to refuse rather than mislead.

What this is not

This is not full xdist support. Worker→controller aggregation (via workeroutput/pytest_testnodedown) is deferred until there's real demand for parallel jamb runs. This PR only closes the silent-corruption path.

How

  • New _xdist_active() helper detects both sides of a distributed run: worker processes (config.workerinput) and the controller (config.option.dist != "no"). Serial runs — including -n0 — keep dist == "no" and are unaffected.
  • pytest_configure raises pytest.UsageError when --jamb is combined with a distributed run.
  • Docs: note the limitation in the pytest integration guide.

Testing

  • Unit tests cover the guard logic and _xdist_active branches directly using SimpleNamespace configs — these run in CI with no xdist dependency.
  • An integration test exercises the real pytest -n 2 path and self-skips via importorskip("xdist") when pytest-xdist isn't installed (verified to pass when xdist is present, skip when not).
  • pytest-xdist is intentionally not added as a dependency.

Full suite: 1482 passed, 1 skipped (the xdist integration test); ruff + mypy clean.

🤖 Generated with Claude Code

jamb collects test-to-requirement coverage on a single per-process
RequirementCollector. Under pytest-xdist (-n / --dist) tests execute on
worker processes whose outcomes are never aggregated back to the
controller, so the generated traceability matrix would be silently
incomplete or empty. For an IEC 62304 compliance artifact a silently
wrong matrix is worse than none.

Detect distributed runs (worker `workerinput`, or controller `dist`
mode != "no") in pytest_configure and fail with a clear UsageError when
combined with --jamb. Serial runs (including -n0) are unaffected.

Full xdist *support* (worker->controller aggregation) is deferred; this
just closes the silent-corruption path.

Guard logic is unit-tested without requiring xdist as a dependency; an
integration test exercises the real `-n` path and self-skips when
pytest-xdist is not installed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vanandrew vanandrew mentioned this pull request Jun 16, 2026
@codecov

codecov Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.80%. Comparing base (134347b) to head (89b114c).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #31   +/-   ##
=======================================
  Coverage   91.79%   91.80%           
=======================================
  Files          27       27           
  Lines        3877     3880    +3     
  Branches      885      886    +1     
=======================================
+ Hits         3559     3562    +3     
  Misses        198      198           
  Partials      120      120           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

The _xdist_active helper's `def` line was never counted by coverage:
pytest loads the plugin via its entry point before pytest-cov starts, so
every top-level def in this module reads as uncovered. That single new
uncovered line pushed the patch below the 85% codecov gate even though
the guard logic is fully exercised.

Inline the trivial worker/controller predicate into pytest_configure so
the patch adds only measurable (and covered) lines. Behavior is
unchanged and still tested via pytest_configure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vanandrew
vanandrew merged commit b20c0a1 into main Jun 16, 2026
9 checks passed
@vanandrew
vanandrew deleted the feat/xdist-guard branch June 16, 2026 04:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant