pyteastrainer
A pytest plugin that fails the run when tests add no coverage, are too slow, or should be one parametrized test, and prints the exact changes that make it green. The minimal suite is solved exactly as an integer program (HiGHS).
pip install pyteastrainer
pytest --strain
Output
============================== pyteastrainer: RED ==============================
25 passed tests cover 41 branches; 9 of them (0.01 s of 0.02 s) cover all of it. To make teastrainer green:
delete tests/test_cart.py::test_bad_coupon_rejected (duplicate of tests/test_cart.py::test_unknown_coupon)
delete tests/test_cart.py::test_coupon_is_stored: every branch it reaches is reached by tests/test_cart.py::test_pct_coupon
drop cases [0-1.0], [1--1.0] from the parametrize of tests/test_cart.py::test_add_rejects: ...
parametrize: merge tests/test_cart.py::test_abs_coupon_floors_at_zero, test_pct_coupon into one test:
@pytest.mark.parametrize('p0, p1, p2', [(2.0, 'FIVEOFF', 5.0), (200.0, 'TEN', 180.0)], ids=[...])
def test_abs_coupon_floors_at_zero(p0, p1, p2):
...
Removing these leaves a suite with the same coverage, 9 tests, 0.01 s, that teastrainer passes.
Apply every action and rerun. A test that asserts something coverage cannot
see is marked @pytest.mark.strain_exempt(reason="...") and always kept.
cd demo && pytest --strain reproduces the full output.
Options
| Option (ini) | Default | Meaning |
|---|---|---|
--strain |
off | Record per-test coverage and gate |
--strain-source PATH (strain_source) |
rootdir minus tests | Production code to measure |
--strain-lines (strain_lines) |
branches | Measure lines instead of branch arcs |
--strain-order (strain_order) |
count,time |
Fewest tests then least runtime, or time,count |
--strain-max-time S (strain_max_time) |
off | Tests slower than S are RED |
--strain-parametrize (strain_parametrize) |
fail |
Parametrize merge suggestions: fail, warn, off |
--strain-baseline FILE (strain_baseline) |
none | Accepted findings; only new ones fail |
--strain-update-baseline |
Write current findings to the baseline | |
--strain-time-limit S (strain_time_limit) |
60 | HiGHS seconds per solver stage |
--strain-report FILE (strain_report) |
none | JSON report |
--strain-show N / --strain-show-slow N |
20 / 3 | Action lines / advisory speed lines |
--strain-warn-only |
Report without changing the exit status | |
--strain-select |
Run only the minimal suite of the last recording | |
--strain-select-coverage F (strain_select_coverage) |
1 | With select: least runtime reaching coverage fraction F |
pytest-cov and xdist
pytest -n auto --cov=src --cov-branch --cov-context=test --strain
Per-test contexts are required. On Python 3.14 set COVERAGE_CORE=ctrace.
Docs
- docs/algorithm.md: formulations, convergence, parametrize detection, benchmark
- docs/releasing.md
Development
pip install -e .[test]
OMP_NUM_THREADS=2 MKL_NUM_THREADS=2 OPENBLAS_NUM_THREADS=2 pytest -n auto --cov
black --check . && pylint pyteastrainer tests
Metadata
Release files for pyteastrainer 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pyteastrainer-0.2.1.tar.gz | 30.6 kB | With provenance | Details for pyteastrainer-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pyteastrainer-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for pyteastrainer-0.2.1-py3-none-any.whl |
Total release size: 55.3 kB
Release files / pyteastrainer-0.2.1.tar.gz
| Download URL | pyteastrainer-0.2.1.tar.gz |
|---|---|
| Size | 30.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b761809a3dfeb2820ba59cd013e2677dfa5f7c23def9638e7eed436008b60340
|
|
BLAKE2b-256 checksum How to use checksums |
5c877766766da1dbbd4ed51fdee102684067182a98fbcbed50644e5a53c112b4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logRelease files / pyteastrainer-0.2.1-py3-none-any.whl
| Download URL | pyteastrainer-0.2.1-py3-none-any.whl |
|---|---|
| Size | 24.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3690f5584e7dea0ade58d36f5a46c7a5db1af9938f7f6686d78eefdefb7f0f47
|
|
BLAKE2b-256 checksum How to use checksums |
d13e1760a337098578ff81a53e6fd96773124ace141aab2eaf0928892ed95a2f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logSecurity for pyteastrainer 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pyteastrainer-0.2.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.