Add remove_finalizer function
This commit is contained in:
parent
eb8b3ad929
commit
791805984b
1
AUTHORS
1
AUTHORS
|
@ -285,6 +285,7 @@ Roberto Polli
|
||||||
Roland Puntaier
|
Roland Puntaier
|
||||||
Romain Dorgueil
|
Romain Dorgueil
|
||||||
Roman Bolshakov
|
Roman Bolshakov
|
||||||
|
Roni Kishner
|
||||||
Ronny Pfannschmidt
|
Ronny Pfannschmidt
|
||||||
Ross Lawley
|
Ross Lawley
|
||||||
Ruaridh Williamson
|
Ruaridh Williamson
|
||||||
|
|
|
@ -730,6 +730,11 @@ Here's how the previous example would look using the ``addfinalizer`` method:
|
||||||
It's a bit longer than yield fixtures and a bit more complex, but it
|
It's a bit longer than yield fixtures and a bit more complex, but it
|
||||||
does offer some nuances for when you're in a pinch.
|
does offer some nuances for when you're in a pinch.
|
||||||
|
|
||||||
|
In addition you can use the remove_finalizer method to remove a finalizer you added
|
||||||
|
to the teardown stage.
|
||||||
|
The remove_finalizer method will remove the first finalizer match it finds and return True,
|
||||||
|
if no match was found the function will return None.
|
||||||
|
|
||||||
.. code-block:: pytest
|
.. code-block:: pytest
|
||||||
|
|
||||||
$ pytest -q test_emaillib.py
|
$ pytest -q test_emaillib.py
|
||||||
|
|
|
@ -760,6 +760,11 @@ class SubRequest(FixtureRequest):
|
||||||
within the requesting test context finished execution."""
|
within the requesting test context finished execution."""
|
||||||
self._fixturedef.addfinalizer(finalizer)
|
self._fixturedef.addfinalizer(finalizer)
|
||||||
|
|
||||||
|
def remove_finalizer(self, finalizer: Callable[[], object]) -> None:
|
||||||
|
"""Remove finalizer/teardown function to be called after the last test
|
||||||
|
within the requesting test context finished execution."""
|
||||||
|
return self._fixturedef.remove_finalizer(finalizer)
|
||||||
|
|
||||||
def _schedule_finalizers(
|
def _schedule_finalizers(
|
||||||
self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest"
|
self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest"
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -1003,6 +1008,12 @@ class FixtureDef(Generic[FixtureValue]):
|
||||||
def addfinalizer(self, finalizer: Callable[[], object]) -> None:
|
def addfinalizer(self, finalizer: Callable[[], object]) -> None:
|
||||||
self._finalizers.append(finalizer)
|
self._finalizers.append(finalizer)
|
||||||
|
|
||||||
|
def remove_finalizer(self, finalizer: Callable[[], object]) -> None:
|
||||||
|
for finalizer_index, finalizer_func in enumerate(self._finalizers):
|
||||||
|
if finalizer_func.__qualname__ == finalizer.__qualname__:
|
||||||
|
del self._finalizers[finalizer_index]
|
||||||
|
return True
|
||||||
|
|
||||||
def finish(self, request: SubRequest) -> None:
|
def finish(self, request: SubRequest) -> None:
|
||||||
exc = None
|
exc = None
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -503,6 +503,20 @@ class SetupState:
|
||||||
assert node in self.stack, (node, self.stack)
|
assert node in self.stack, (node, self.stack)
|
||||||
self.stack[node][0].append(finalizer)
|
self.stack[node][0].append(finalizer)
|
||||||
|
|
||||||
|
def remove_finalizer(self, finalizer: Callable[[], object], node: Node) -> None:
|
||||||
|
"""Remove a finalizer in the given node by name.
|
||||||
|
|
||||||
|
The node must be currently active in the stack.
|
||||||
|
The first finalizer by name will be removed.
|
||||||
|
"""
|
||||||
|
assert node and not isinstance(node, tuple)
|
||||||
|
assert callable(finalizer)
|
||||||
|
assert node in self.stack, (node, self.stack)
|
||||||
|
for finalizer_index, finalizer_func in enumerate(self.stack[node][0]):
|
||||||
|
if finalizer_func.__qualname__ == finalizer.__qualname__:
|
||||||
|
del self.stack[node][0][finalizer_index]
|
||||||
|
return True
|
||||||
|
|
||||||
def teardown_exact(self, nextitem: Optional[Item]) -> None:
|
def teardown_exact(self, nextitem: Optional[Item]) -> None:
|
||||||
"""Teardown the current stack up until reaching nodes that nextitem
|
"""Teardown the current stack up until reaching nodes that nextitem
|
||||||
also descends from.
|
also descends from.
|
||||||
|
|
|
@ -857,11 +857,33 @@ class TestRequestBasic:
|
||||||
parent = item.getparent(pytest.Module)
|
parent = item.getparent(pytest.Module)
|
||||||
assert parent is not None
|
assert parent is not None
|
||||||
teardownlist = parent.obj.teardownlist
|
teardownlist = parent.obj.teardownlist
|
||||||
|
item.session._setupstate.teardown_exact(None)
|
||||||
|
assert teardownlist == [1]
|
||||||
|
|
||||||
|
def test_request_remove_finalizer(self, pytester: Pytester) -> None:
|
||||||
|
item = pytester.getitem(
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
teardownlist = []
|
||||||
|
@pytest.fixture
|
||||||
|
def something(request):
|
||||||
|
request.addfinalizer(lambda: teardownlist.append(1))
|
||||||
|
request.remove_finalizer(lambda: teardownlist.append(1))
|
||||||
|
def test_func(something): pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
assert isinstance(item, Function)
|
||||||
|
item.session._setupstate.setup(item)
|
||||||
|
item._request._fillfixtures()
|
||||||
|
# successively check finalization calls
|
||||||
|
parent = item.getparent(pytest.Module)
|
||||||
|
assert parent is not None
|
||||||
|
teardownlist = parent.obj.teardownlist
|
||||||
ss = item.session._setupstate
|
ss = item.session._setupstate
|
||||||
assert not teardownlist
|
assert not teardownlist
|
||||||
ss.teardown_exact(None)
|
ss.teardown_exact(None)
|
||||||
print(ss.stack)
|
print(ss.stack)
|
||||||
assert teardownlist == [1]
|
assert teardownlist == []
|
||||||
|
|
||||||
def test_request_addfinalizer_failing_setup(self, pytester: Pytester) -> None:
|
def test_request_addfinalizer_failing_setup(self, pytester: Pytester) -> None:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
|
Loading…
Reference in New Issue