-
- Notifications
You must be signed in to change notification settings - Fork 3.1k
Closed
Labels
topic: fixturesanything involving fixtures directly or indirectlyanything involving fixtures directly or indirectly
Description
I've noticed a corner case where a failure during fixture cleanup code can crash pytest when --exitfirst is set. Minimal reproduction example is below. Note that a very similar crash can also be observed with no --exitfirst but a KeyboardInterrupt instead. Another minimal example is also provided below.
pytest and operating system versions
Windows 10
python 3.10.8
pytest 7.2.0
Minimal example:
test_exit_first.py content:
import pytest @pytest.fixture(scope="module") # mind the scope def fixture(): yield assert False def test_1(fixture): assert False def test_2(): # mind the presence of another test after the first failing one pass$ PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest test_exit_first.py -v -x ================================= test session starts ================================== platform win32 -- Python 3.10.8, pytest-7.2.0, pluggy-1.0.0 -- D:\Python310\python.exe cachedir: .pytest_cache rootdir: D:\tmp collected 2 items test_exit_first.py::test_1 FAILED [ 50%] Traceback (most recent call last): File "D:\Python310\lib\runpy.py", line 196, in _run_module_as_main return _run_code(code, main_globals, None, File "D:\Python310\lib\runpy.py", line 86, in _run_code exec(code, run_globals) File "D:\Python310\Scripts\pytest.exe\__main__.py", line 7, in <module> sys.exit(console_main()) File "D:\Python310\lib\site-packages\_pytest\config\__init__.py", line 190, in console_main code = main() File "D:\Python310\lib\site-packages\_pytest\config\__init__.py", line 167, in main ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main( File "D:\Python310\lib\site-packages\pluggy\_hooks.py", line 265, in __call__ return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) File "D:\Python310\lib\site-packages\pluggy\_manager.py", line 80, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "D:\Python310\lib\site-packages\pluggy\_callers.py", line 60, in _multicall return outcome.get_result() File "D:\Python310\lib\site-packages\pluggy\_result.py", line 60, in get_result raise ex[1].with_traceback(ex[2]) File "D:\Python310\lib\site-packages\pluggy\_callers.py", line 39, in _multicall res = hook_impl.function(*args) File "D:\Python310\lib\site-packages\_pytest\main.py", line 317, in pytest_cmdline_main return wrap_session(config, _main) File "D:\Python310\lib\site-packages\_pytest\main.py", line 305, in wrap_session config.hook.pytest_sessionfinish( File "D:\Python310\lib\site-packages\pluggy\_hooks.py", line 265, in __call__ return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) File "D:\Python310\lib\site-packages\pluggy\_manager.py", line 80, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "D:\Python310\lib\site-packages\pluggy\_callers.py", line 55, in _multicall gen.send(outcome) File "D:\Python310\lib\site-packages\_pytest\terminal.py", line 808, in pytest_sessionfinish outcome.get_result() File "D:\Python310\lib\site-packages\pluggy\_result.py", line 60, in get_result raise ex[1].with_traceback(ex[2]) File "D:\Python310\lib\site-packages\pluggy\_callers.py", line 39, in _multicall res = hook_impl.function(*args) File "D:\Python310\lib\site-packages\_pytest\runner.py", line 106, in pytest_sessionfinish session._setupstate.teardown_exact(None) File "D:\Python310\lib\site-packages\_pytest\runner.py", line 530, in teardown_exact raise exc File "D:\Python310\lib\site-packages\_pytest\runner.py", line 523, in teardown_exact fin() File "D:\Python310\lib\site-packages\_pytest\fixtures.py", line 684, in <lambda> subrequest.node.addfinalizer(lambda: fixturedef.finish(request=subrequest)) File "D:\Python310\lib\site-packages\_pytest\fixtures.py", line 1036, in finish raise exc File "D:\Python310\lib\site-packages\_pytest\fixtures.py", line 1029, in finish func() File "D:\Python310\lib\site-packages\_pytest\fixtures.py", line 916, in _teardown_yield_fixture next(it) File "D:\tmp\test_exit_first.py", line 6, in fixture assert False AssertionError: assert False Alternative KeyboardInterrupt example
test_keyboard_interrupt.py
import pytest import time @pytest.fixture(scope="module") def fixture(): yield assert False def test_1(fixture): time.sleep(1) # Ctrl-C here$ PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest test_keyboard_interrupt.py -v ============================================== test session starts =============================================== platform win32 -- Python 3.10.8, pytest-7.2.0, pluggy-1.0.0 -- D:\Python310\python.exe cachedir: .pytest_cache rootdir: D:\tmp collected 1 item test_keyboard_interrupt.py::test_1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! D:\tmp\test_keyboard_interrupt.py:10: KeyboardInterrupt (to show a full traceback on KeyboardInterrupt use --full-trace) Traceback (most recent call last): File "D:\Python310\lib\runpy.py", line 196, in _run_module_as_main return _run_code(code, main_globals, None, File "D:\Python310\lib\runpy.py", line 86, in _run_code exec(code, run_globals) File "D:\Python310\Scripts\pytest.exe\__main__.py", line 7, in <module> sys.exit(console_main()) File "D:\Python310\lib\site-packages\_pytest\config\__init__.py", line 190, in console_main code = main() File "D:\Python310\lib\site-packages\_pytest\config\__init__.py", line 167, in main ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main( File "D:\Python310\lib\site-packages\pluggy\_hooks.py", line 265, in __call__ return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) File "D:\Python310\lib\site-packages\pluggy\_manager.py", line 80, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "D:\Python310\lib\site-packages\pluggy\_callers.py", line 60, in _multicall return outcome.get_result() File "D:\Python310\lib\site-packages\pluggy\_result.py", line 60, in get_result raise ex[1].with_traceback(ex[2]) File "D:\Python310\lib\site-packages\pluggy\_callers.py", line 39, in _multicall res = hook_impl.function(*args) File "D:\Python310\lib\site-packages\_pytest\main.py", line 317, in pytest_cmdline_main return wrap_session(config, _main) File "D:\Python310\lib\site-packages\_pytest\main.py", line 305, in wrap_session config.hook.pytest_sessionfinish( File "D:\Python310\lib\site-packages\pluggy\_hooks.py", line 265, in __call__ return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) File "D:\Python310\lib\site-packages\pluggy\_manager.py", line 80, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "D:\Python310\lib\site-packages\pluggy\_callers.py", line 55, in _multicall gen.send(outcome) File "D:\Python310\lib\site-packages\_pytest\terminal.py", line 808, in pytest_sessionfinish outcome.get_result() File "D:\Python310\lib\site-packages\pluggy\_result.py", line 60, in get_result raise ex[1].with_traceback(ex[2]) File "D:\Python310\lib\site-packages\pluggy\_callers.py", line 39, in _multicall res = hook_impl.function(*args) File "D:\Python310\lib\site-packages\_pytest\runner.py", line 106, in pytest_sessionfinish session._setupstate.teardown_exact(None) File "D:\Python310\lib\site-packages\_pytest\runner.py", line 530, in teardown_exact raise exc File "D:\Python310\lib\site-packages\_pytest\runner.py", line 523, in teardown_exact fin() File "D:\Python310\lib\site-packages\_pytest\fixtures.py", line 684, in <lambda> subrequest.node.addfinalizer(lambda: fixturedef.finish(request=subrequest)) File "D:\Python310\lib\site-packages\_pytest\fixtures.py", line 1036, in finish raise exc File "D:\Python310\lib\site-packages\_pytest\fixtures.py", line 1029, in finish func() File "D:\Python310\lib\site-packages\_pytest\fixtures.py", line 916, in _teardown_yield_fixture next(it) File "D:\tmp\test_keyboard_interrupt.py", line 7, in fixture assert False AssertionError: assert False Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
topic: fixturesanything involving fixtures directly or indirectlyanything involving fixtures directly or indirectly