diff --git a/pyproject.toml b/pyproject.toml index 342d54d1..2a4b1f3c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -209,7 +209,35 @@ all_bullets = true [tool.pytest.ini_options] minversion = '6.0' -timeout = 200 # per-test hard limit +# NOTE: `pytest-timeout`'s global per-test cap is intentionally +# NOT set — both of its enforcement methods break trio's +# runtime under our fork-based spawn backends: +# +# - `method='signal'` (the default; SIGALRM) raises `Failed` +# synchronously from the signal handler in trio's main +# thread, which leaves `GLOBAL_RUN_CONTEXT` half-installed +# ("Trio guest run got abandoned"). EVERY subsequent +# `trio.run()` in the same pytest session then bails with +# `RuntimeError: Attempted to call run() from inside a +# run()` — full-session poison: a single 200s hang +# cascades into 30+ false-positive failures across +# downstream test files. +# +# - `method='thread'` calls `_thread.interrupt_main()` which +# can let the resulting `KeyboardInterrupt` escape trio's +# `KIManager` under fork-cascade teardown races, killing +# the whole pytest session. +# +# For tests that legitimately need a wall-clock cap, use +# `with trio.fail_after(N):` INSIDE the test — trio's own +# Cancelled machinery handles the timeout cleanly through +# the actor nursery without disturbing global state. See +# `tests/test_advanced_streaming.py::test_dynamic_pub_sub`'s +# module-level NOTE for the canonical pattern. +# +# CI environments should rely on job-level wall-clock +# timeouts (e.g. GitHub Actions `timeout-minutes`) for an +# escape hatch on genuinely-stuck suites. # https://docs.pytest.org/en/stable/reference/reference.html#configuration-options testpaths = [ 'tests'