move fixture finalizing to standalone hook
This commit is contained in:
parent
108f99086d
commit
86a3ed6ae4
|
@ -1015,31 +1015,8 @@ class FixtureDef(Generic[FixtureValue]):
|
|||
self._finalizers.append(finalizer)
|
||||
|
||||
def finish(self, request: SubRequest) -> None:
|
||||
exceptions: List[BaseException] = []
|
||||
while self._finalizers:
|
||||
fin = self._finalizers.pop()
|
||||
try:
|
||||
fin()
|
||||
except BaseException as e:
|
||||
exceptions.append(e)
|
||||
node = request.node
|
||||
if len(exceptions) == 1:
|
||||
final_exception = exceptions[0]
|
||||
elif len(exceptions) > 1:
|
||||
msg = f'errors while tearing down fixture "{self.argname}" of {node}'
|
||||
final_exception = BaseExceptionGroup(msg, exceptions[::-1])
|
||||
else:
|
||||
final_exception = None
|
||||
node.ihook.pytest_fixture_post_finalizer(
|
||||
fixturedef=self, request=request, exception=final_exception
|
||||
)
|
||||
# Even if finalization fails, we invalidate the cached fixture
|
||||
# value and remove all finalizers because they may be bound methods
|
||||
# which will keep instances alive.
|
||||
self.cached_result = None
|
||||
self._finalizers.clear()
|
||||
if final_exception:
|
||||
raise final_exception
|
||||
node.ihook.pytest_fixture_teardown(fixturedef=self, request=request)
|
||||
|
||||
def execute(self, request: SubRequest) -> FixtureValue:
|
||||
"""Return the value of this fixture, executing it if not cached."""
|
||||
|
@ -1151,6 +1128,30 @@ def pytest_fixture_setup(
|
|||
return result
|
||||
|
||||
|
||||
def pytest_fixture_teardown(
|
||||
fixturedef: FixtureDef[FixtureValue], request: SubRequest
|
||||
) -> None:
|
||||
exceptions: List[BaseException] = []
|
||||
while fixturedef._finalizers:
|
||||
fin = fixturedef._finalizers.pop()
|
||||
try:
|
||||
fin()
|
||||
except BaseException as e:
|
||||
exceptions.append(e)
|
||||
node = request.node
|
||||
node.ihook.pytest_fixture_post_finalizer(fixturedef=fixturedef, request=request)
|
||||
# Even if finalization fails, we invalidate the cached fixture
|
||||
# value and remove all finalizers because they may be bound methods
|
||||
# which will keep instances alive.
|
||||
fixturedef.cached_result = None
|
||||
fixturedef._finalizers.clear()
|
||||
if len(exceptions) == 1:
|
||||
raise exceptions[0]
|
||||
elif len(exceptions) > 1:
|
||||
msg = f'errors while tearing down fixture "{fixturedef.argname}" of {node}'
|
||||
raise BaseExceptionGroup(msg, exceptions[::-1])
|
||||
|
||||
|
||||
def wrap_function_to_error_out_if_called_directly(
|
||||
function: FixtureFunction,
|
||||
fixture_marker: "FixtureFunctionMarker",
|
||||
|
|
|
@ -860,10 +860,28 @@ def pytest_fixture_setup(
|
|||
"""
|
||||
|
||||
|
||||
def pytest_fixture_teardown(
|
||||
fixturedef: "FixtureDef[Any]", request: "SubRequest"
|
||||
) -> None:
|
||||
"""Perform fixture teardown execution.
|
||||
|
||||
:param fixturdef:
|
||||
The fixture definition object.
|
||||
:param request:
|
||||
The fixture request object.
|
||||
|
||||
Use in conftest plugins
|
||||
=======================
|
||||
|
||||
Any conftest file can implement this hook. For a given fixture, only
|
||||
conftest files in the fixture scope's directory and its parent directories
|
||||
are consulted.
|
||||
"""
|
||||
|
||||
|
||||
def pytest_fixture_post_finalizer(
|
||||
fixturedef: "FixtureDef[Any]",
|
||||
request: "SubRequest",
|
||||
exception: "BaseException | None",
|
||||
) -> None:
|
||||
"""Called after fixture teardown, but before the cache is cleared, so
|
||||
the fixture result ``fixturedef.cached_result`` is still available (not
|
||||
|
@ -873,8 +891,6 @@ def pytest_fixture_post_finalizer(
|
|||
The fixture definition object.
|
||||
:param request:
|
||||
The fixture request object.
|
||||
:param exception:
|
||||
An exception raised in the finalisation of the fixtures.
|
||||
|
||||
Use in conftest plugins
|
||||
=======================
|
||||
|
|
|
@ -4014,7 +4014,7 @@ def test_pytest_fixture_setup_and_post_finalizer_hook(pytester: Pytester) -> Non
|
|||
)
|
||||
|
||||
|
||||
def test_exceptions_in_pytest_fixture_setup_and_post_finalizer_hook(
|
||||
def test_exceptions_in_pytest_fixture_setup_and_pytest_fixture_teardown(
|
||||
pytester: Pytester,
|
||||
) -> None:
|
||||
pytester.makeconftest(
|
||||
|
@ -4024,8 +4024,10 @@ def test_exceptions_in_pytest_fixture_setup_and_post_finalizer_hook(
|
|||
def pytest_fixture_setup(fixturedef):
|
||||
result = yield
|
||||
print('SETUP EXCEPTION in {0}: {1}'.format(fixturedef.argname, result.exception))
|
||||
def pytest_fixture_post_finalizer(fixturedef, exception):
|
||||
print('TEARDOWN EXCEPTION in {0}: {1}'.format(fixturedef.argname, exception))
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
def pytest_fixture_teardown(fixturedef):
|
||||
result = yield
|
||||
print('TEARDOWN EXCEPTION in {0}: {1}'.format(fixturedef.argname, result.exception))
|
||||
"""
|
||||
)
|
||||
pytester.makepyfile(
|
||||
|
|
Loading…
Reference in New Issue