`faulthandler_timeout` stops covering a test once setup, call or a subtest fails (`pytest_exception_interact` cancels the timer)
Los mantenedores suelen responder en 1 día
@XXXXXQ-0206 ya está trabajando en esto.
Desde el 15/10/2026.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 78/100
Línea de trabajo
El error está en el hookimpl pytest_exception_interact de src/_pytest/faulthandler.py (alrededor de las líneas 113-119), que cancela el temporizador de faulthandler en fallos ordinarios. Empieza leyendo ese hook junto a pytest_enter_pdb, que debe seguir siendo el único lugar que cancela el temporizador para el depurador. Está terminado cuando el ejemplo mínimo de tres archivos del issue vuelca un traceback a los 2 s y sale, --pdb sigue cancelando el temporizador, y se actualiza el parámetro test_cancel_timeout_on_hook en testing/test_faulthandler.py, con una nueva prueba de pytester para un test fallido cuyo teardown se cuelga.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
- a detailed description of the bug or problem you are having
- output of
pip listfrom the virtual environment you are using - pytest and operating system versions
- minimal example if possible
Description
The docs say faulthandler_timeout "Dumps the tracebacks of all threads if a test takes longer than X seconds to run (including fixture setup and teardown)". In practice the timer is cancelled at the first failure in a test. Everything after that failure runs with no timeout: the fixture teardown and, with subtests, the rest of the test body. So when a fixture teardown hangs after a failed test, no traceback is printed. With faulthandler_exit_on_timeout = true the process also does not exit, although exiting on a hang in CI is the reason that option exists.
Cause (line numbers are from 9.1.1 and are unchanged on main):
src/_pytest/faulthandler.py:88-100:pytest_runtest_protocolarmsfaulthandler.dump_traceback_later()once per item and cancels it infinally.src/_pytest/faulthandler.py:113-119: the plugin also implementspytest_exception_interactand callsfaulthandler.cancel_dump_traceback_later()there.src/_pytest/runner.py:257-258:call_and_reportcallspytest_exception_interactfor every setup, call or teardown exception that passescheck_interactive_exception(runner.py:270-285). That covers every failure except a skip or an xfail, whether or not--pdbis given.src/_pytest/subtests.py:274-277andsrc/_pytest/unittest.py:464-467do the same for each failing subtest.
As a result, a hookimpl meant for the debugger also runs on every ordinary failure.
The debugger case does not need this hookimpl:
pytestPDB._init_pdbcallspytest_enter_pdb(src/_pytest/debugging.py:275), both for--pdbpost-mortem (debugging.py:400) and forbreakpoint()/set_trace(debugging.py:282).- The plugin already cancels the timer in its
pytest_enter_pdbhook (faulthandler.py:105-110).
The hookimpl came from pytest-faulthandler (pytest-dev/pytest-faulthandler#14, #15), which copied it from pytest-timeout, and it moved into core with #5441. pytest-timeout had the same bug (pytest-dev/pytest-timeout#196). It was fixed by deleting the pytest_exception_interact hookimpl and relying on pytest_enter_pdb (pytest-dev/pytest-timeout#197, released in 2.5).
Minimal example
pytest.ini:
[pytest]
faulthandler_timeout = 2
test_teardown_hang.py:
import time
import pytest
@pytest.fixture
def slow_teardown():
yield
time.sleep(6)
def test_fails_then_teardown_hangs(slow_teardown):
assert False
def test_passes_then_teardown_hangs(slow_teardown):
pass
test_setup_raises.py:
import time
import pytest
@pytest.fixture
def slow_teardown():
yield
time.sleep(6)
@pytest.fixture
def broken_setup(slow_teardown):
raise RuntimeError("setup failed")
def test_setup_raises_then_teardown_hangs(broken_setup):
pass
test_subtest_then_hang.py:
import time
def test_failing_subtest_then_body_hangs(subtests):
with subtests.test("first"):
assert False
time.sleep(6)
Each file was run on its own with pytest -p no:cacheprovider -q -o faulthandler_exit_on_timeout=true <target>:
| target | traceback dump | wall time |
|---|---|---|
test_passes_then_teardown_hangs |
yes, at 2 s, then exit | 2.2 s |
test_fails_then_teardown_hangs |
none | 6.2 s |
test_setup_raises.py |
none | 6.3 s |
test_subtest_then_hang.py |
none | 6.3 s |
The output of test_fails_then_teardown_hangs is just the failure. No Timeout (0:00:02)! appears, although the teardown ran for 6 s:
F [100%]
=================================== FAILURES ===================================
________________________ test_fails_then_teardown_hangs ________________________
...
E assert False
=========================== short test summary info ============================
FAILED test_teardown_hang.py::test_fails_then_teardown_hangs - assert False
1 failed in 6.01s
Expected: every row dumps the traceback at 2 s, which shows the sleeping frame in slow_teardown or in the test body, and then exits.
I deleted only the pytest_exception_interact hookimpl from src/_pytest/faulthandler.py and changed nothing else. With that change, all four rows dump at 2 s and exit at about 2.1 s. --pdb still cancels the timer: running test_fails_then_teardown_hangs with --pdb and waiting 3 s at the post-mortem prompt (past the 2 s timeout) before c produced no dump, the same as unpatched 9.1.1.
Suggested fix
- Delete the
pytest_exception_interacthookimpl fromsrc/_pytest/faulthandler.py. Timer cancellation for the debugger stays withpytest_enter_pdb. - In
testing/test_faulthandler.py, drop the"pytest_exception_interact"parameter fromtest_cancel_timeout_on_hook. - Add a pytester test in which a failing test's fixture teardown sleeps past
faulthandler_timeout, and assert*Timeout*on stderr.
Versions
- pytest 9.1.1. The same code is on
mainat c9c19f8 and has been since 5.0.0. - Python 3.14.8
- Ubuntu 26.04.1 LTS, Linux 7.0.0, x86_64
$ pip list
Package Version
--------- -------
iniconfig 2.3.1
packaging 26.3
pluggy 1.6.0
pygments 2.21.0
pytest 9.1.1
- Lenguaje dominante
- Python
- Estrellas
- 14.6k
- Forks
- 3.5k
- Merge medio
- 3 d 18 h
- PR fusionados (30 d)
- 27
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de pytest-dev/pytest
-
Docs build fails with Pluggy 1.7.0 on an unresolved private DistFacade referencePosiblemente ocupada @Lothnic la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
pytest-dev/pytest#15190 ·
Los mantenedores suelen responder en 1 día
-
Assertion diff doesn't pretty-print the built-in frozen dict (Python 3.15)Posiblemente ocupada @HakeemTheEmperor la tomó hace 3 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
pytest-dev/pytest#15172 ·
Los mantenedores suelen responder en 1 día
-
monkeypatch.setattr fails to undo on objects with a custom __setattr__ (regression from #14969)Posiblemente ocupada @hardikkaurani la tomó hace 22 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
pytest-dev/pytest#15099 · 6 comentarios ·
Los mantenedores suelen responder en 1 día
-
Allow dotted test filenames (`*.test.py`) via one-line change to `compute_module_name`Quizá libre de nuevo @siddy-stack la tomó hace 59 días y no hay ningún pull request abierto. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
pytest-dev/pytest#14514 · 6 comentarios ·
Los mantenedores suelen responder en 1 día
-
Expose CaptureManager as public APIQuizá libre de nuevo @harsh21234i la tomó hace 197 días y no hay ningún pull request abierto. Abiertotype: enhancement type: feature-branch
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
pytest-dev/pytest#14186 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de pytest-dev/pytest
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
PolicyEngine/policyengine-us#10262 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
kellyjonbrazil/jc#788 ·
Los mantenedores suelen responder en 2 días
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día
-
`/search.json` ignores the documented `editions.sort` parameterPosiblemente ocupada @PranavD2905 la tomó hoy. AbiertoAffects: Server Good First Issue Module: Solr Needs: Triage Theme: Public APIs Theme: Search
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
internetarchive/openlibrary#13989 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
bug P2: misleading query
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
jeffknupp/association#478 ·