Summary
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.
Reproduction Code
Create these two files in an empty directory.
conftest.py:
from pathlib import Path
import pytest
MARKER = Path(__file__).with_name("finalizer-ran")
@pytest.fixture
def resource(request):
request.addfinalizer(lambda: MARKER.write_text("ran", encoding="utf-8"))
raise KeyboardInterrupt
test_example.py:
def test_setup(resource):
pass
Run pytest, then check whether the finalizer marker was created:
python -m pytest -q test_example.py
python -c "from pathlib import Path; print(Path('finalizer-ran').exists())"
Actual Behavior
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:
$ python -m pytest --version
pytest 9.1.1
$ python -m pip list
Package Version
--------- -------
iniconfig 2.3.0
packaging 26.3
pip 26.2.1
pluggy 1.6.0
Pygments 2.21.0
pytest 9.1.1
$ python -VV
Python 3.12.3 (main, Jan 22 2026, 20:57:42) [GCC 13.3.0]
$ uname -srm
Linux 6.8.0-124-generic x86_64
$ grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Ubuntu 24.04.4 LTS"
Summary
If a fixture registers a finalizer and its setup is interrupted by
KeyboardInterruptor anotherBaseExceptionthat is not handled bypytest_fixture_setup, the registered finalizer is not executed during teardown. This can leave resources created before theinterruption open or otherwise unreleased.
Reproduction Code
Create these two files in an empty directory.
conftest.py:test_example.py:Run pytest, then check whether the finalizer marker was created:
Actual Behavior
Pytest stops with the
KeyboardInterruptfrom fixture setup and exits with code2.The finalizer marker is not created:
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: