Add a parallel tox runner with per-environment progress bars#14690
Add a parallel tox runner with per-environment progress bars#14690laurac8r wants to merge 12 commits into
Conversation
Co-authored-by: Claude
run_env created the Popen locally but never assigned it to state.proc, leaving TestSubprocessCleanup.test_proc_stored_on_state_for_cleanup red. Assign immediately after creation so callers can terminate a running env. Co-authored-by: Claude Code - Fable 5, Opus 4.8, Sonnet 5
Plain pyXY envs have no pytest-xdist (tox.ini installs it only for the xdist factor), so unconditionally passing '-n auto' failed them with 'unrecognized arguments: -n' (exit 4). build_cmd() now adds '-n auto' only when 'xdist' is a dash-token of the env name — and still re-feeds it to xdist envs, since explicit posargs replace the env's defaults. Drop '-q': it suppresses the 'collected N items' line and the '='-delimited summary, so status never left 'collecting' and every count stayed 0. Without '-q', pytest's end-of-run 'short test summary info' recap re-lists failures; a guard stops progress-char counting once that section starts to avoid double-counting. Co-authored-by: Claude Code - Fable 5, Opus 4.8, Sonnet 5
terminate_all() sends terminate() to each still-running tracked proc (skipping finished and never-started ones, swallowing the poll/exit race), and main() now catches KeyboardInterrupt to invoke it and return 130. Cursor restore still runs via the existing finally. Co-authored-by: Claude Code - Fable 5, Opus 4.8, Sonnet 5
Cover uv-run usage and the -p concurrency cap, the xdist factor rule (-n auto only for *-xdist envs, re-supplied because posargs replace tox defaults), why -q must never be added, non-pytest spinner envs, Ctrl-C teardown (exit 130), and exit-code semantics. Co-authored-by: Claude Code - Fable 5, Opus 4.8, Sonnet 5
Co-authored-by: Claude Code - Fable 5, Opus 4.8, Sonnet 5
Co-authored-by: Claude Code - Fable 5, Opus 4.8, Sonnet 5
There was a problem hiding this comment.
Pull request overview
Adds a new contributor-facing helper under scripts/ to run multiple tox environments concurrently and render a live, per-environment progress display (bars for pytest envs, spinner for non-pytest envs), with unit tests and minor repo hygiene updates.
Changes:
- Add
scripts/tox_progress.pyparallel tox runner with live progress rendering and Ctrl-C termination behavior. - Add
scripts/test_tox_progress.pyunit tests covering parsing/command construction/cleanup behavior. - Update repo metadata files (
AUTHORS,.gitignore).
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| scripts/tox_progress.py | New parallel tox runner with output parsing + progress UI. |
| scripts/test_tox_progress.py | New unit tests for tox_progress helper. |
| AUTHORS | Adds contributor name. |
| .gitignore | Removes an ignore entry (unrelated to tox runner). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from unittest.mock import MagicMock | ||
| from unittest.mock import patch | ||
|
|
||
| from tox_progress import build_cmd | ||
| from tox_progress import EnvState | ||
| from tox_progress import parse_summary_line | ||
| from tox_progress import run_env | ||
| from tox_progress import strip_ansi | ||
| from tox_progress import terminate_all | ||
|
|
||
| import pytest |
| for raw_line in proc.stdout: | ||
| line = raw_line.rstrip("\n") | ||
| state.output_lines.append(line) | ||
| state.elapsed = time.time() - state.start_time | ||
|
|
||
| # xdist: detect worker startup | ||
| clean_check = strip_ansi(line) |
|
tox already has a parallel mode. The output improvements are nice, but I'm -1 on this for a variety of reasons. All in all, I don't think some fancy progress bars are worth having some 500 lines of rather complex/hacky code (e.g. parsing output instead of integrating as a pytest plugin, etc.). Feel free to maintain this as a separate project of course (I suppose it maybe could be generalized to work outside of pytest's repo, or maybe even be a tox plugin or something?), but I don't think this should live in the pytest repo. |
Definitely agree. Thanks anyway for the contribution. |
Adds
scripts/tox_progress.py, a contributor helper that runs multiple toxenvironments concurrently and renders a live per-environment progress bar
(collection count, pass/fail/skip tallies, elapsed time) in place of tox's
serial, interleaved output. Handy for local pre-push sweeps across
py310–py314,linting, and friends.This is contributor tooling under
scripts/— not part of the shippedpytestpackage, and it changes no runtime behavior.
What it does
uvx tox run -e <env>, in parallel threads (all at once, orcapped with
-p N).(linting, docs, …) render a spinner.
-n autoon thexdistenv-name factor, matching howtox.iniconditions thepytest-xdistdependency — plainpyXYenvs runsequentially,
*-xdistenvs run parallel.130; otherwiseexits
1if any env failed, else0. Failed envs get their last 30 outputlines echoed after the final render.
Usage
Testing
24 unit tests in
scripts/test_tox_progress.pycover ANSI stripping, summaryparsing, the
build_cmdfactor-gating contract, the short-test-summarydouble-count guard, and
terminate_allteardown semantics.pre-commit run --all-filespasses clean.Checklist
factor rule, Ctrl-C behavior, and exit codes).
scripts/test_tox_progress.py, 24 tests).AUTHORS.changelog/<PR#>.contrib.rst).Co-authored-by:commit trailers.