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)
|
self._finalizers.append(finalizer)
|
||||||
|
|
||||||
def finish(self, request: SubRequest) -> None:
|
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
|
node = request.node
|
||||||
if len(exceptions) == 1:
|
node.ihook.pytest_fixture_teardown(fixturedef=self, request=request)
|
||||||
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
|
|
||||||
|
|
||||||
def execute(self, request: SubRequest) -> FixtureValue:
|
def execute(self, request: SubRequest) -> FixtureValue:
|
||||||
"""Return the value of this fixture, executing it if not cached."""
|
"""Return the value of this fixture, executing it if not cached."""
|
||||||
|
@ -1151,6 +1128,30 @@ def pytest_fixture_setup(
|
||||||
return result
|
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(
|
def wrap_function_to_error_out_if_called_directly(
|
||||||
function: FixtureFunction,
|
function: FixtureFunction,
|
||||||
fixture_marker: "FixtureFunctionMarker",
|
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(
|
def pytest_fixture_post_finalizer(
|
||||||
fixturedef: "FixtureDef[Any]",
|
fixturedef: "FixtureDef[Any]",
|
||||||
request: "SubRequest",
|
request: "SubRequest",
|
||||||
exception: "BaseException | None",
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Called after fixture teardown, but before the cache is cleared, so
|
"""Called after fixture teardown, but before the cache is cleared, so
|
||||||
the fixture result ``fixturedef.cached_result`` is still available (not
|
the fixture result ``fixturedef.cached_result`` is still available (not
|
||||||
|
@ -873,8 +891,6 @@ def pytest_fixture_post_finalizer(
|
||||||
The fixture definition object.
|
The fixture definition object.
|
||||||
:param request:
|
:param request:
|
||||||
The fixture request object.
|
The fixture request object.
|
||||||
:param exception:
|
|
||||||
An exception raised in the finalisation of the fixtures.
|
|
||||||
|
|
||||||
Use in conftest plugins
|
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,
|
pytester: Pytester,
|
||||||
) -> None:
|
) -> None:
|
||||||
pytester.makeconftest(
|
pytester.makeconftest(
|
||||||
|
@ -4024,8 +4024,10 @@ def test_exceptions_in_pytest_fixture_setup_and_post_finalizer_hook(
|
||||||
def pytest_fixture_setup(fixturedef):
|
def pytest_fixture_setup(fixturedef):
|
||||||
result = yield
|
result = yield
|
||||||
print('SETUP EXCEPTION in {0}: {1}'.format(fixturedef.argname, result.exception))
|
print('SETUP EXCEPTION in {0}: {1}'.format(fixturedef.argname, result.exception))
|
||||||
def pytest_fixture_post_finalizer(fixturedef, exception):
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
print('TEARDOWN EXCEPTION in {0}: {1}'.format(fixturedef.argname, exception))
|
def pytest_fixture_teardown(fixturedef):
|
||||||
|
result = yield
|
||||||
|
print('TEARDOWN EXCEPTION in {0}: {1}'.format(fixturedef.argname, result.exception))
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
|
Loading…
Reference in New Issue