You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Fixture finalizers are skipped when setup is interrupted before cached_result is assigned #15067
If a fixture registers a finalizer and its setup is interrupted by KeyboardInterrupt or another BaseException that is not handled by pytest_fixture_setup, the registered finalizer is not executed during teardown. This can leave resources created before the
interruption open or otherwise unreleased.
Pytest stops with the KeyboardInterrupt from fixture setup and exits with code 2.
The finalizer marker is not created:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
path/to/conftest.py:12: KeyboardInterrupt
no tests ran in 1.38s
False
Expected Behavior
Once request.addfinalizer() has successfully registered a finalizer, pytest should run that finalizer during teardown even if the fixture setup later raises an interruption.The marker should be created before pytest exits.
This is also the documented behavior for request.addfinalizer(): pytest's fixture documentation states that a finalizer is run once it has been added, even if the fixture raises after adding it.
Environment
The repro requires no third-party plugins. Verified on a clean virtualenv:
Reproduced on main (9.2.0.dev450, Python 3.13): the marker file is not created, so the finalizer is skipped.
What I see is that this only happens for the base exceptions pytest re-raises itself. call_and_report() re-raises Exit and KeyboardInterrupt straight away, so runtestprotocol() never reaches pytest_runtest_teardown, and with it SetupState.teardown_exact(), which is what runs the finalizers registered so far. An ordinary exception in the fixture is reported instead of re-raised, the protocol continues to the teardown phase, and the finalizer runs -- which matches the documentation in doc/en/how-to/fixtures.rst: "pytest will run that finalizer once it's been added, even if that fixture raises an exception after adding the finalizer".
So there is a gap between that sentence and what happens on an interrupt, but I am not sure the fix is obvious: running teardown before propagating a KeyboardInterrupt makes Ctrl+C slower and risks a hanging finalizer blocking the exit, which may be why the interrupt is re-raised eagerly in the first place.
Before writing anything: is running the already-registered finalizers on an interrupt the behaviour you want here, and if so would you accept a pull request for it? If not, the alternative would be to qualify the documentation sentence instead. Happy either way.
Disclosure per the project's AI/LLM policy: this investigation was AI-assisted; I ran the reproduction on main and traced the code path myself before asking.
I reproduced this behavior on main and read through the existing discussion. I’m interested in helping validate the regression test and understand the teardown semantics around KeyboardInterrupt. Is there a specific test case or review task where a new contributor could help?
Activity
Use explicit file encoding in KeyboardInterrupt regression test (pyte…
Address review: nested try/finally for teardown cleanup; add teardown…
Add changelog entry for pytest-dev#15067
Tejas5405 commentedon Oct 1, 2026
Reproduced on main (9.2.0.dev450, Python 3.13): the marker file is not created, so the finalizer is skipped.
What I see is that this only happens for the base exceptions pytest re-raises itself.
call_and_report()re-raisesExitandKeyboardInterruptstraight away, soruntestprotocol()never reachespytest_runtest_teardown, and with itSetupState.teardown_exact(), which is what runs the finalizers registered so far. An ordinary exception in the fixture is reported instead of re-raised, the protocol continues to the teardown phase, and the finalizer runs -- which matches the documentation indoc/en/how-to/fixtures.rst: "pytest will run that finalizer once it's been added, even if that fixture raises an exception after adding the finalizer".So there is a gap between that sentence and what happens on an interrupt, but I am not sure the fix is obvious: running teardown before propagating a
KeyboardInterruptmakes Ctrl+C slower and risks a hanging finalizer blocking the exit, which may be why the interrupt is re-raised eagerly in the first place.Before writing anything: is running the already-registered finalizers on an interrupt the behaviour you want here, and if so would you accept a pull request for it? If not, the alternative would be to qualify the documentation sentence instead. Happy either way.
Disclosure per the project's AI/LLM policy: this investigation was AI-assisted; I ran the reproduction on main and traced the code path myself before asking.
HigorMonteiro commentedon Oct 3, 2026
I reproduced this behavior on main and read through the existing discussion. I’m interested in helping validate the regression test and understand the teardown semantics around
KeyboardInterrupt. Is there a specific test case or review task where a new contributor could help?