Skip to main content

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_file

    • check_for_crash_file(path) -> dict | None
  • Runner helpers (library module): pytest_abort.abort_handling

    • handle_abort(json_file, html_file, last_running_file, testfile, crash_info=None) -> bool
    • append_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-abort is installed (editable or wheel), pytest auto-loads it via the pytest11 entry 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 PYTHONPATH only, 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 set PYTEST_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 if PYTEST_ABORT_CRASHED_TESTS_LOG is 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 leading pytest ... to run as python -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 (or PYTEST_ABORT_LAST_RUNNING_DIR for xdist)
  • Produce per-run JSON/HTML artifacts with pytest-json-report and pytest-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-jsonblob payloads 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_abort is importable by the pytest subprocess (either by installing pytest-abort into the environment, or by adding the repo checkout to PYTHONPATH)
  • Enables the plugin via the installed pytest11 entry point (no -p needed when installed). If using PYTHONPATH only, load explicitly with -p pytest_abort.plugin.
  • Sets PYTEST_ABORT_LAST_RUNNING_FILE per 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.html using pytest_abort.abort_handling.handle_abort(...)
  • Sanitizes per-file HTML jsonblobs before merging:
    • sanitize_all_html_jsonblobs("./logs") then pytest_html_merger

run_multi_gpu.py

  • Uses the same plugin and env-var mechanism for its pytest subprocesses
  • Uses the same ./logs directory 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.json and *_log.html exist 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_abort-0.1.0.tar.gz (28.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_abort-0.1.0-py3-none-any.whl (25.4 kB view details)

Uploaded Python 3

File details

Details for the file pytest_abort-0.1.0.tar.gz.

File metadata

  • Download URL: pytest_abort-0.1.0.tar.gz
  • Upload date:
  • Size: 28.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for pytest_abort-0.1.0.tar.gz
Algorithm Hash digest
SHA256 fe159f359b0b6446c18281ab87492e9a3730af2107b850f3e951c12b0ddd114f
MD5 4690c0bae998d3f61712492d714bf7ce
BLAKE2b-256 d8202c37634a8ef2a507628fb09e3ee4889fb21f75a7f3ee0f3f006ac1658671

See more details on using hashes here.

File details

Details for the file pytest_abort-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pytest_abort-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for pytest_abort-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6304dc1a592d5375121f0dba57ff52058d11349d8c7c4b26ac229c384d6c39a1
MD5 3780d03fc6ba75398b57246b75c35b63
BLAKE2b-256 6927daf06ac15b265c92f63395083ea4fa8cda1a5dcdbcb80b95149b071a8ac7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page