Skip to main content

pytest-poolwatch

See whether your pytest concurrency pool is actually full.

PyPI Python pytest CI License: MIT Status: Alpha

Concurrency profiling and scheduler-underfill diagnostics for pytest.

Documentation · Examples · JSON schema · Issues

pytest-poolwatch reconstructs when tests actually overlapped and shows whether configured execution slots stayed busy while runnable tests were still queued. It observes public pytest reports; it does not replace the scheduler, runner, or fixture lifecycle.

Why PoolWatch?

Ordinary duration reports tell you which tests were slow. PoolWatch answers a different question: did the scheduler keep the available concurrency busy?

  • Measure peak and time-weighted average concurrency.
  • Separate scheduler underfill from normal end-of-suite drain.
  • Quantify utilization and idle slot-seconds.
  • Inspect active and queued test timelines.
  • Export versioned JSON and a self-contained HTML report.
  • Work without a server, database, agent, or private pytest API.

Installation

python -m pip install pytest-poolwatch

With uv:

uv add --dev pytest-poolwatch

Installing the package is enough for pytest to discover its pytest11 plugin entry point.

Quick start

pytest --poolwatch --poolwatch-target=40

PoolWatch adds a summary after the normal pytest result:

============================= PoolWatch summary =============================
Configured concurrency:                 40
Target source:                command_line
Peak active tests:                      40
Average active tests:                 32.60
Concurrency utilization:             81.5%
Scheduler underfill:                17m 23s
Peak queued tests:                     126
Idle slot-seconds:                 4,912.00

Generate machine-readable and visual reports at the same time:

pytest --poolwatch \
  --poolwatch-target=40 \
  --poolwatch-json=.poolwatch/run.json \
  --poolwatch-html=.poolwatch/run.html

The HTML report is a portable, read-only notebook containing concurrency and queue charts, underfill windows, pytest phase totals, and the slowest attempts.

The diagnostic that matters

PoolWatch does not label every idle slot as a scheduling problem:

State Queue Active tests Diagnosis
Work is waiting and capacity is unused > 0 < target Scheduler underfill
No work remains to start 0 < target Normal suite drain
Capacity is unknown any observed peak Baseline only; pass an explicit target for a definitive diagnosis

This distinction is what exposed the refill bug fixed by pytest-asyncio-cooperative PR #86: the controlled pre-fix workload measured 34.2% utilization and 0.885s of underfill, while the fixed scheduler measured 73.1% utilization with no material underfill. Exact timings depend on the machine; the behavioral assertions do not.

Configuration

Command-line values take precedence over pytest configuration:

[tool.pytest.ini_options]
poolwatch = true
poolwatch_target = 40
poolwatch_json = ".poolwatch/run.json"
poolwatch_html = ".poolwatch/run.html"
poolwatch_underfill_threshold = 0.1
CLI option Purpose
--poolwatch Enable profiling and the terminal summary.
--poolwatch-target=N Set the expected active-test capacity.
--poolwatch-json=PATH Write schema-versioned JSON and enable PoolWatch.
--poolwatch-html=PATH Write self-contained HTML and enable PoolWatch.
--poolwatch-underfill-threshold=SECONDS Ignore shorter underfill windows.

Exclude a deliberately unrepresentative test:

import pytest


@pytest.mark.poolwatch_ignore
def test_one_off_migration():
    ...

See the configuration guide and metrics reference for the full behavior.

Compatibility

Runner or plugin Status Capacity source
pytest Supported Serial capacity of 1
pytest-asyncio Supported Serial test protocols
pytest-xdist Supported Numeric workers, or observed workers for auto
pytest-asyncio-cooperative Supported on its own max_asyncio_tasks
pytest-asyncio-concurrent Conservative support Explicit target or observed peak
Custom scheduler Supported with configuration --poolwatch-target=N
pytest-xdist + pytest-asyncio-cooperative Unsupported upstream combination Both plugins replace overlapping runtest-loop behavior

When both schedulers are detected in an active run, PoolWatch prefers the xdist worker count rather than inventing a combined capacity. Merely installing xdist does not suppress cooperative-only capacity detection. Do not enable the two schedulers together; their execution hooks conflict independently of PoolWatch.

PoolWatch relies on public pytest hooks and report timestamps. Compatibility details and known limitations are documented in the compatibility guide.

Documentation

Development

git clone https://github.com/Butterski/pytest-poolwatch.git
cd pytest-poolwatch
uv sync --locked --dev
uv run ruff check .
uv run ruff format --check .
uv run ty check
uv run coverage run -m pytest
uv run coverage combine
uv run coverage report
uv build

The test matrix covers Python 3.11–3.14. Releases are built from GitHub Releases and published through PyPI Trusted Publishing.

Scope

Version 0.1 measures test overlap, configured capacity, queued work, utilization, and scheduler underfill. It does not currently measure event-loop lag or attribute blocking calls. poolwatch_blocking is a documentation marker reserved for that future work.

PoolWatch is distributed under the MIT License. Contributions and reproducible scheduler workloads are welcome.

Release files for pytest-poolwatch 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-poolwatch 0.1.1
File Size Uploaded
pytest_poolwatch-0.1.1.tar.gz 17.5 kB Details

Built distribution (wheel)

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

Total release size: 38.3 kB

Release files / pytest_poolwatch-0.1.1.tar.gz

Download URL pytest_poolwatch-0.1.1.tar.gz
Size 17.5 kB
Tags Source
SHA-256 checksum
How to use checksums
d589ef8801df3909359e915c8ee14e4136aa5881d61170955dfb6af1361bcd64
BLAKE2b-256 checksum
How to use checksums
14a3fd435408dc3f0e9734a38f469810e4174b41c7cb4271f6d0eec3227732b4
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 Jul 29, 2026.

Transparency log

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

Download URL pytest_poolwatch-0.1.1-py3-none-any.whl
Size 20.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e3a27ccfe178f63e7a9266f9e0736e8735fa37c3ab6626d30b12aaba40dcc0ff
BLAKE2b-256 checksum
How to use checksums
206bfa49930c5beb27e22c6d76248f87cc53b4e810fb9bc29910fe93bd025df0
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 Jul 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

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