pytest-timeout

A pytest plugin that terminates hanging or excessively slow tests and dumps a stack trace when it does

Tool
PyPI
v2.4.0
260 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
62 /100 Good
Development Activity 68
Maintenance 24
Community 76
Maturity 60
Momentum 20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
77 /100 Good
Architecture 74
Code Quality 78
Innovation 65
Learning Curve 90

pytest-timeout is a pytest plugin that times every test and aborts it when it exceeds a configured duration, printing a stack dump of all running threads so you can diagnose why a test hung. It exists specifically to catch deadlocks and runaway tests in CI, not to enforce precise performance budgets — the README is explicit that timeouts should be a last resort, not an expected part of a healthy test suite.

Under the pytest-dev GitHub organization alongside pytest itself, the plugin supports two interruption strategies (a portable thread method and a POSIX signal method), configurable globally via --timeout, an ini setting, or the PYTEST_TIMEOUT environment variable, or per-test via the @pytest.mark.timeout() marker. With roughly 19 million weekly PyPI downloads, it’s one of the most widely installed pytest plugins for taming flaky or hanging test suites in continuous integration.

What You Get

  • Global timeout configuration via --timeout CLI flag, PYTEST_TIMEOUT env var, or the [pytest] timeout ini option
  • Per-test overrides via the @pytest.mark.timeout(seconds) decorator marker
  • Two termination strategies: a portable thread method and a faster POSIX signal-based method
  • Automatic stack dumps of all running threads printed to stderr when a timeout fires
  • Debugger detection that suppresses timeouts automatically during interactive --pdb or breakpoint sessions
  • Two extension hooks (pytest_timeout_set_timer / pytest_timeout_cancel_timer) for plugins like pytest-asyncio to customize timeout behavior

Common Use Cases

  • Preventing a CI pipeline from hanging indefinitely when a test deadlocks or blocks on an unresponsive external call
  • Diagnosing intermittent test hangs by inspecting the thread stack dump printed at timeout
  • Setting a global safety-net timeout across a large test suite while overriding it per-test for known slow integration tests
  • Combining with pytest-forked to fully isolate and recover from hard-terminated hanging tests

Under The Hood

Architecture — The entire plugin lives in a single ~550-line pytest_timeout.py module implementing pytest hook specifications (pytest_runtest_protocol, pytest_configure) that wrap each test item with a timer. The thread method spawns a watchdog thread that calls os._exit() on the whole process if the timer fires (hard termination, sacrificing teardown/JUnit output for certainty), while the signal method schedules a SIGALRM that raises inside the test via pytest’s own failure mechanism, allowing the suite to continue — a well-documented tradeoff spelled out in the README rather than hidden.

Tech Stack — Pure Python with zero runtime dependencies beyond pytest itself; the pyproject.toml build backend is plain setuptools. It targets Python 3.7+ and PyPy3, and CI covers a matrix of versions via tox.ini.

Code Quality — A single 658-line test_pytest_timeout.py test module (roughly matching the implementation’s line count) exercises both timeout methods, marker precedence, and debugger-detection behavior; ruff.toml and a pre-commit CI badge indicate linting is enforced. Development pace is slow but steady (0.33 commits/month recently, 274 total commits since 2019, moderate activity), consistent with a small, feature-complete utility rather than a churning codebase.

API Design — The public surface is intentionally tiny: a CLI flag, an ini option, an env var, and one marker, all converging on the same Settings namedtuple internally, which makes the common case (pytest --timeout=300) a one-line addition to any existing pytest invocation with no code changes required.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers