Pytest plugin + helpers for attributing hard crashes (SIGSEGV/SIGABRT) to the last running test and keeping pytest-html reports mergeable.
Project description
pytest-abort
pytest-abort is a pytest plugin + helper library to attribute hard crashes (SIGSEGV/SIGABRT) to the last running test and to keep pytest-html reports mergeable and renderable by sanitizing data-jsonblob payloads before pytest_html_merger runs.
What this repo contains
-
Pytest plugin:
pytest_abort.plugin- Writes a JSON “last-running test” marker file before each test starts.
- Deletes the marker file on normal test completion.
- If pytest hard-crashes, cleanup never runs and the marker file remains with
status="running".
-
Crash marker parser:
pytest_abort.crash_filecheck_for_crash_file(path) -> dict | None
-
Runner helpers (library module):
pytest_abort.abort_handlinghandle_abort(json_file, html_file, last_running_file, testfile, crash_info=None) -> boolappend_abort_to_json(...),append_abort_to_html(...)sanitize_html_file_jsonblob(path),sanitize_all_html_jsonblobs(log_dir)
Key concept: the last-running marker file
The plugin writes a small JSON file (path supplied by the runner) like:
{
"test_name": "test_foo",
"nodeid": "tests/test_bar.py::TestBar::test_foo",
"start_time": "2026-01-14T23:59:59.123456",
"status": "running",
"pid": 12345,
"gpu_id": "0"
}
If pytest exits normally, the file is deleted. If pytest is killed by a segfault/abort, the file remains and the outer runner can attribute the crash.
Installation
Editable install:
python3 -m pip install -e .
If you plan to use -n (parallel execution) and/or per-test timeouts, you likely also want:
python3 -m pip install -U pytest-xdist pytest-timeout
Build a wheel
Build the wheel from the repo root:
python3 -m pip install --upgrade build
python3 -m build
The wheel is produced under:
./dist/(for example:./dist/pytest_abort-0.1.0-py3-none-any.whl)
Install the wheel:
python3 -m pip install ./dist/*.whl
Using the plugin directly (debugging)
Recommended (env var):
PYTEST_ABORT_LAST_RUNNING_FILE=/tmp/last_running.json \
python3 -m pytest -q tests/test_something.py
Note:
- If
pytest-abortis installed (editable or wheel), pytest auto-loads it via thepytest11entry point, so you do not need-p .... - If the plugin is installed and you want to load it explicitly anyway, use
-p pytest_abort. - If the plugin is not installed and you’re loading it via
PYTHONPATHonly, use-p pytest_abort.plugin. - Don’t use
-p ...when it’s already auto-loaded, or pytest will error with “Plugin already registered”.
Optional CLI override:
python3 -m pytest \
--last-running-file /tmp/last_running.json \
-q tests/test_something.py
Crashed-tests log (optional)
You can also write a shared crashed tests log (JSONL: one JSON object per line).
- Set
PYTEST_ABORT_CRASHED_TESTS_LOG=/path/to/crashed_tests.jsonl - For
pytest -n(xdist), also setPYTEST_ABORT_LAST_RUNNING_DIR=/path/to/dir(so each worker writes its own marker file).
Example:
export PYTEST_ABORT_LAST_RUNNING_DIR=/tmp/last_running
export PYTEST_ABORT_CRASHED_TESTS_LOG=/tmp/crashed_tests.jsonl
pytest -n 8 tests
Notes:
- In xdist, the master process appends to the crashed-tests log when a worker goes down.
- In runner flows (like
run_single_gpu.py),handle_abort(...)appends to the crashed-tests log ifPYTEST_ABORT_CRASHED_TESTS_LOGis set.
Crash recovery for xdist runs (optional helper)
If you want a “crash recovery” loop for pytest -n ..., you can use the included outer-process wrapper:
pytest-abort-retry --max-runs 5 --clear-crash-log -- \
pytest -n 8 --max-worker-restart=50 --tb=short --maxfail=20 tests examples
Per-test timeout example (requires pytest-timeout):
pytest-abort-retry --max-runs 5 --clear-crash-log -- \
pytest -n 8 --max-worker-restart=50 --tb=short --maxfail=20 \
--timeout=600 --timeout-method=thread \
tests examples
This will:
- run pytest
- read
PYTEST_ABORT_CRASHED_TESTS_LOG - re-run pytest with
--deselect=<nodeid>for crashed nodeids until stable (or--max-runs).
Note:
- The wrapper supports the standard
... -- pytest ...form. - To avoid “wrong pytest binary / wrong environment” problems (missing
-n, missing--timeout, etc.), the wrapper rewrites a leadingpytest ...to run aspython -m pytest ...using the wrapper’s interpreter.
Integration notes (outer runner)
If you run pytest from an outer process (CI wrapper, custom runner, etc.), a common pattern is:
- Add this package to the environment (editable install or wheel)
- Set
PYTEST_ABORT_LAST_RUNNING_FILE(orPYTEST_ABORT_LAST_RUNNING_DIRfor xdist) - Produce per-run JSON/HTML artifacts with
pytest-json-reportandpytest-html(best-effort) - If a hard crash occurred, patch/repair the per-run artifacts from the outer process via
handle_abort(...) - Before merging many HTML reports, sanitize
data-jsonblobpayloads so merge/HTML rendering stays robust
How rocm-jax uses it
The rocm-jax test runners use pytest-abort to attribute hard crashes to the last-running test and to keep pytest-html reports mergeable.
run_single_gpu.py
- Ensures
pytest_abortis importable by the pytest subprocess (either by installingpytest-abortinto the environment, or by adding the repo checkout toPYTHONPATH) - Enables the plugin via the installed
pytest11entry point (no-pneeded when installed). If usingPYTHONPATHonly, load explicitly with-p pytest_abort.plugin. - Sets
PYTEST_ABORT_LAST_RUNNING_FILEper test-file run (logs/*_last_running.json) - On crash: re-runs remaining tests in the same file using
--deselect <crashed-nodeid> - Appends crash info into
*_log.json+*_log.htmlusingpytest_abort.abort_handling.handle_abort(...) - Sanitizes per-file HTML jsonblobs before merging:
sanitize_all_html_jsonblobs("./logs")thenpytest_html_merger
run_multi_gpu.py
- Uses the same plugin and env-var mechanism for its pytest subprocesses
- Uses the same
./logsdirectory and does not archive logs
Using the helper library from a runner (example)
Hard crashes can prevent pytest-html / pytest-json-report from finishing their output files. The pattern used by the ROCm runners is:
- Run pytest with
--html=...and--json-report-file=...(best-effort) - Detect a hard crash via the last-running marker file
- Call
pytest_abort.abort_handling.handle_abort(...)from the runner process to ensure the per-testfile*_log.jsonand*_log.htmlexist and contain a synthetic “crashed” test entry
Minimal example:
import os
import subprocess
from pytest_abort.abort_handling import handle_abort, sanitize_all_html_jsonblobs
json_log = "logs/example_log.json"
html_log = "logs/example_log.html"
last_running = "logs/example_last_running.json"
env = os.environ.copy()
env["PYTEST_ABORT_LAST_RUNNING_FILE"] = os.path.abspath(last_running)
subprocess.run(
[
"python3",
"-m",
"pytest",
# Plugin is auto-loaded via pytest11 entry point when installed.
"--json-report",
f"--json-report-file={json_log}",
f"--html={html_log}",
"tests/some_test_file.py",
],
env=env,
check=False,
)
# If a crash happened, this ensures JSON/HTML logs exist and are patched:
handle_abort(json_log, html_log, last_running, testfile="some_test_file")
# Before merging many per-file HTML reports:
sanitize_all_html_jsonblobs("logs")
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pytest_abort-0.1.0.post1.tar.gz.
File metadata
- Download URL: pytest_abort-0.1.0.post1.tar.gz
- Upload date:
- Size: 28.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f9cd99ad5eda03c1014715a93c3090eff8e9a070a8fd95aa57f7fde0d13bd2b
|
|
| MD5 |
b0742af81f895daec27ec0da368655e6
|
|
| BLAKE2b-256 |
eb6c8b0b781cf6ed99a513e40ba204ff69b0afcf7e54ebfb702e07c08eea2d53
|
File details
Details for the file pytest_abort-0.1.0.post1-py3-none-any.whl.
File metadata
- Download URL: pytest_abort-0.1.0.post1-py3-none-any.whl
- Upload date:
- Size: 25.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f127a983ea1fb52bc77cc7628d607463fdc95cd43d911569780b30859d01f6eb
|
|
| MD5 |
d5dbfa1a164097c2a28bf8389d1b590e
|
|
| BLAKE2b-256 |
8493aa64109b7c2f72a4fa3d9090bda625387b0b2b5d91b5deef6b957778c5e9
|