Skip to main content

pytest-threadbudget

tests

Opt-in BLAS/OpenMP thread ceilings for local pytest-xdist workers. Installing the plugin alone leaves tests unchanged. Python 3.11+, pytest 8–9, pytest-xdist 3.6+.

Quick start

Install and enable it in your test environment:

python -m pip install pytest-threadbudget pytest-xdist
python -m pytest -n 4 --threadbudget=auto

To develop and test from this source directory:

python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[test,realrepos]"
python -m pytest tests -q
python -m pytest examples/test_matrix.py -n 2 --threadbudget=auto --threadbudget-report=work/example.json -q

The public source is available on GitHub. You can also install the local checkout or built wheel. Follow VALIDATE.md for complete commands, real upstream test subsets and an optional macOS OpenBLAS profile. See RESULTS.md for measured results and their limits.

What it does

--threadbudget=auto computes max(1, available_cpus // worker_count) as a per-native-pool thread ceiling. joblib.cpu_count() accounts for supported CPU affinity and container quota constraints. Optional --threadbudget-cpus=N lowers that allocation budget; it does not set OS affinity or impose a CPU quota.

The plugin sets common native thread environment hints in each worker at pytest_configure, applies runtime caps to supported already-loaded pools, and rediscovers pools at each test boundary. Runtime caps never raise an existing tighter limit. JSON reports aggregate plans, observed pool settings, outcomes, and missing/crashed-worker diagnostics in the controller process. Schema version 2 retains minimum/maximum thread counts and violation counts across all recorded boundaries; the final snapshot cannot erase an earlier violation.

The implementation builds on threadpoolctl and joblib. The integration is motivated by pytest-xdist issue #1012. It is an independent alpha project with no upstream endorsement or adoption claim.

Enable it in a project

Install this plugin in the project's test environment, then add:

[tool.pytest.ini_options]
threadbudget = "auto"

Keep the project's normal -n configuration. For one run, CLI options override the INI setting:

python -m pytest -n 4 --threadbudget=auto
python -m pytest -n 4 --threadbudget=1
python -m pytest -n 4 --threadbudget=off

Off is the default. An explicit positive number is a per-worker per-pool ceiling. If the worker/thread allocation exceeds the CPU budget, the plugin warns; it does not change xdist's worker count. Serial pytest execution is also supported.

Explicit settings and cleanup

If any of OMP_NUM_THREADS, OPENBLAS_NUM_THREADS, MKL_NUM_THREADS, BLIS_NUM_THREADS, or VECLIB_MAXIMUM_THREADS is already defined, the plugin preserves all existing settings and skips applying its budget. The report states why. Use --threadbudget-override-env to explicitly select a plugin ceiling. This conservative policy includes empty environment values.

Changed environment values and runtime settings of pools present when budgeting starts are restored at pytest shutdown, including normal test failure paths. Per-test runtime contexts are restored after fixture/test teardown. Libraries first initialized under the plugin's environment retain their initialization defaults after shutdown; their hypothetical pre-import defaults cannot be reconstructed. Forced process termination cannot run Python cleanup.

Boundaries

  • Applies to local -n workers; explicit --tx destinations are rejected when budgeting is enabled. CPU allocation across different remote hosts is out of scope.
  • Apple Accelerate is not controlled by threadpoolctl. Environment hints and an empty pool list are not proof of enforcement. Reports say so explicitly.
  • Manages supported BLAS/OpenMP APIs, not Numba, PyTorch interop pools, NumExpr, GPU kernels, Python executors, subprocess trees, or machine-wide concurrency.
  • The number is a ceiling for each supported native pool, not a hard OS limit on total live threads or nested parallelism across multiple runtimes. Some native APIs apply to the calling thread rather than every Python thread.
  • pytest_configure runs after initial conftest imports. Their already-loaded pools can be limited, but earlier import-time computation is not controlled.
  • Libraries loaded inside a test receive environment hints; runtime discovery catches them at subsequent boundaries. Tests can deliberately change settings inside their own bodies. The plugin is not a sandbox or permanent watchdog.
  • Rediscovery and optional reporting add overhead. Existing project limits can already solve oversubscription; speedups are workload-dependent.

Benchmark fairly

python -m pytest_threadbudget.benchmark --output work/bench-01 --workers 2 --repeats 3 --warmups 1 -- examples/test_matrix.py -q
python scripts/validate_real_repos.py --output work/upstream-01 --workers 2 --repeats 3 --warmups 1

The first command is synthetic. The second uses selected original tests from installed NumPy/SciPy/scikit-learn releases. It does not run complete repositories or imply adoption. Benchmarks alternate execution order, preserve raw logs, compare individual JUnit outcomes and keep slowdowns visible. Headline timing comparisons are suppressed if test outcomes differ or runtime enforcement cannot be verified. Full details and return codes are in VALIDATE.md.

Layout and development

  • src/pytest_threadbudget/budget.py: pure planning and environment policy.
  • src/pytest_threadbudget/plugin.py: pytest hooks, lifecycle and reports.
  • src/pytest_threadbudget/benchmark.py: isolated comparisons and sampling.
  • tests/: planning, real subprocess/xdist/native-runtime and failure tests.
  • scripts/validate_real_repos.py: pinned-by-report upstream release selections.
  • scripts/validate_statsmodels.py: regression tests with early conftest loading.
  • evidence/: validation metadata, raw reports and logs from this machine.
  • .github/workflows/tests.yml: built-wheel Linux/macOS/Windows test matrix.

See CONTRIBUTING.md for development checks, CHANGELOG.md for release notes, and RELEASE.md for the trusted-publishing procedure. Upstream PRs and adoption are tracked separately from package publication.

Metadata

Release files for pytest-threadbudget 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytest-threadbudget 0.1.1
File Size Uploaded Provenance
pytest_threadbudget-0.1.1.tar.gz 374.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pytest-threadbudget 0.1.1
File Interpreter ABI Platform
pytest_threadbudget-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 389.5 kB

Release files / pytest_threadbudget-0.1.1.tar.gz

Download URL pytest_threadbudget-0.1.1.tar.gz
Size 374.1 kB
Tags Source
SHA-256 checksum
How to use checksums
43810423d8ea002a9396011d72f91ddc390c739f3bc57dcac77e7e9d0f33264a
BLAKE2b-256 checksum
How to use checksums
53b7f4a047c0f6d8f082c6552d99471d5f4fe4114274714337141a15b54d7172
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 16, 2026.

Transparency log

Release files / pytest_threadbudget-0.1.1-py3-none-any.whl

Download URL pytest_threadbudget-0.1.1-py3-none-any.whl
Size 15.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ce9d4c0d0ca555cbcfc58525bbbf6d4d2ab2341732f1280b1a59a2bc429a257d
BLAKE2b-256 checksum
How to use checksums
09d38c83b5634a9aa60b1415b70419ec352b612a5188ffcf4fa17bf6f9973bc2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 16, 2026.

Transparency log

Security for pytest-threadbudget 0.1.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.

Select from 2 files

Attestation for pytest_threadbudget-0.1.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 16, 2026.

Transparency log

A 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.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page