Merge pull request #8323 from bluetech/setupstate-refactor-3
runner: a few more tweaks to SetupState
This commit is contained in:
commit
1003beaffa
|
@ -372,7 +372,7 @@ def _fill_fixtures_impl(function: "Function") -> None:
|
|||
fi = fm.getfixtureinfo(function.parent, function.obj, None)
|
||||
function._fixtureinfo = fi
|
||||
request = function._request = FixtureRequest(function, _ispytest=True)
|
||||
fm.session._setupstate.prepare(function)
|
||||
fm.session._setupstate.setup(function)
|
||||
request._fillfixtures()
|
||||
# Prune out funcargs for jstests.
|
||||
newfuncargs = {}
|
||||
|
|
|
@ -509,9 +509,9 @@ def pytest_runtest_teardown(item: "Item", nextitem: Optional["Item"]) -> None:
|
|||
|
||||
:param nextitem:
|
||||
The scheduled-to-be-next test item (None if no further test item is
|
||||
scheduled). This argument can be used to perform exact teardowns,
|
||||
i.e. calling just enough finalizers so that nextitem only needs to
|
||||
call setup-functions.
|
||||
scheduled). This argument is used to perform exact teardowns, i.e.
|
||||
calling just enough finalizers so that nextitem only needs to call
|
||||
setup functions.
|
||||
"""
|
||||
|
||||
|
||||
|
|
|
@ -120,6 +120,8 @@ def runtestprotocol(
|
|||
) -> List[TestReport]:
|
||||
hasrequest = hasattr(item, "_request")
|
||||
if hasrequest and not item._request: # type: ignore[attr-defined]
|
||||
# This only happens if the item is re-run, as is done by
|
||||
# pytest-rerunfailures.
|
||||
item._initrequest() # type: ignore[attr-defined]
|
||||
rep = call_and_report(item, "setup", log)
|
||||
reports = [rep]
|
||||
|
@ -151,7 +153,7 @@ def show_test_item(item: Item) -> None:
|
|||
|
||||
def pytest_runtest_setup(item: Item) -> None:
|
||||
_update_current_test_var(item, "setup")
|
||||
item.session._setupstate.prepare(item)
|
||||
item.session._setupstate.setup(item)
|
||||
|
||||
|
||||
def pytest_runtest_call(item: Item) -> None:
|
||||
|
@ -417,7 +419,7 @@ class SetupState:
|
|||
|
||||
[]
|
||||
|
||||
During the setup phase of item1, prepare(item1) is called. What it does
|
||||
During the setup phase of item1, setup(item1) is called. What it does
|
||||
is:
|
||||
|
||||
push session to stack, run session.setup()
|
||||
|
@ -441,7 +443,7 @@ class SetupState:
|
|||
|
||||
[session]
|
||||
|
||||
During the setup phase of item2, prepare(item2) is called. What it does
|
||||
During the setup phase of item2, setup(item2) is called. What it does
|
||||
is:
|
||||
|
||||
push mod2 to stack, run mod2.setup()
|
||||
|
@ -477,23 +479,26 @@ class SetupState:
|
|||
],
|
||||
] = {}
|
||||
|
||||
def prepare(self, item: Item) -> None:
|
||||
def setup(self, item: Item) -> None:
|
||||
"""Setup objects along the collector chain to the item."""
|
||||
needed_collectors = item.listchain()
|
||||
|
||||
# If a collector fails its setup, fail its entire subtree of items.
|
||||
# The setup is not retried for each item - the same exception is used.
|
||||
for col, (finalizers, prepare_exc) in self.stack.items():
|
||||
if prepare_exc:
|
||||
raise prepare_exc
|
||||
for col, (finalizers, exc) in self.stack.items():
|
||||
assert col in needed_collectors, "previous item was not torn down properly"
|
||||
if exc:
|
||||
raise exc
|
||||
|
||||
needed_collectors = item.listchain()
|
||||
for col in needed_collectors[len(self.stack) :]:
|
||||
assert col not in self.stack
|
||||
# Push onto the stack.
|
||||
self.stack[col] = ([col.teardown], None)
|
||||
try:
|
||||
col.setup()
|
||||
except TEST_OUTCOME as e:
|
||||
self.stack[col] = (self.stack[col][0], e)
|
||||
raise e
|
||||
except TEST_OUTCOME as exc:
|
||||
self.stack[col] = (self.stack[col][0], exc)
|
||||
raise exc
|
||||
|
||||
def addfinalizer(self, finalizer: Callable[[], object], node: Node) -> None:
|
||||
"""Attach a finalizer to the given node.
|
||||
|
@ -517,7 +522,7 @@ class SetupState:
|
|||
while self.stack:
|
||||
if list(self.stack.keys()) == needed_collectors[: len(self.stack)]:
|
||||
break
|
||||
node, (finalizers, prepare_exc) = self.stack.popitem()
|
||||
node, (finalizers, _) = self.stack.popitem()
|
||||
while finalizers:
|
||||
fin = finalizers.pop()
|
||||
try:
|
||||
|
|
|
@ -131,7 +131,7 @@ class TestFillFixtures:
|
|||
item = pytester.getitem(Path("test_funcarg_basic.py"))
|
||||
assert isinstance(item, Function)
|
||||
# Execute's item's setup, which fills fixtures.
|
||||
item.session._setupstate.prepare(item)
|
||||
item.session._setupstate.setup(item)
|
||||
del item.funcargs["request"]
|
||||
assert len(get_public_names(item.funcargs)) == 2
|
||||
assert item.funcargs["some"] == "test_func"
|
||||
|
@ -827,7 +827,7 @@ class TestRequestBasic:
|
|||
req = item._request
|
||||
|
||||
# Execute item's setup.
|
||||
item.session._setupstate.prepare(item)
|
||||
item.session._setupstate.setup(item)
|
||||
|
||||
with pytest.raises(pytest.FixtureLookupError):
|
||||
req.getfixturevalue("notexists")
|
||||
|
@ -855,7 +855,7 @@ class TestRequestBasic:
|
|||
"""
|
||||
)
|
||||
assert isinstance(item, Function)
|
||||
item.session._setupstate.prepare(item)
|
||||
item.session._setupstate.setup(item)
|
||||
item._request._fillfixtures()
|
||||
# successively check finalization calls
|
||||
parent = item.getparent(pytest.Module)
|
||||
|
|
|
@ -25,7 +25,7 @@ class TestSetupState:
|
|||
item = pytester.getitem("def test_func(): pass")
|
||||
ss = item.session._setupstate
|
||||
values = [1]
|
||||
ss.prepare(item)
|
||||
ss.setup(item)
|
||||
ss.addfinalizer(values.pop, item)
|
||||
assert values
|
||||
ss.teardown_exact(None)
|
||||
|
@ -34,7 +34,7 @@ class TestSetupState:
|
|||
def test_teardown_exact_stack_empty(self, pytester: Pytester) -> None:
|
||||
item = pytester.getitem("def test_func(): pass")
|
||||
ss = item.session._setupstate
|
||||
ss.prepare(item)
|
||||
ss.setup(item)
|
||||
ss.teardown_exact(None)
|
||||
ss.teardown_exact(None)
|
||||
ss.teardown_exact(None)
|
||||
|
@ -49,9 +49,9 @@ class TestSetupState:
|
|||
)
|
||||
ss = item.session._setupstate
|
||||
with pytest.raises(ValueError):
|
||||
ss.prepare(item)
|
||||
ss.setup(item)
|
||||
with pytest.raises(ValueError):
|
||||
ss.prepare(item)
|
||||
ss.setup(item)
|
||||
|
||||
def test_teardown_multiple_one_fails(self, pytester: Pytester) -> None:
|
||||
r = []
|
||||
|
@ -67,7 +67,7 @@ class TestSetupState:
|
|||
|
||||
item = pytester.getitem("def test_func(): pass")
|
||||
ss = item.session._setupstate
|
||||
ss.prepare(item)
|
||||
ss.setup(item)
|
||||
ss.addfinalizer(fin1, item)
|
||||
ss.addfinalizer(fin2, item)
|
||||
ss.addfinalizer(fin3, item)
|
||||
|
@ -87,7 +87,7 @@ class TestSetupState:
|
|||
|
||||
item = pytester.getitem("def test_func(): pass")
|
||||
ss = item.session._setupstate
|
||||
ss.prepare(item)
|
||||
ss.setup(item)
|
||||
ss.addfinalizer(fin1, item)
|
||||
ss.addfinalizer(fin2, item)
|
||||
with pytest.raises(Exception) as err:
|
||||
|
@ -106,7 +106,7 @@ class TestSetupState:
|
|||
item = pytester.getitem("def test_func(): pass")
|
||||
mod = item.listchain()[-2]
|
||||
ss = item.session._setupstate
|
||||
ss.prepare(item)
|
||||
ss.setup(item)
|
||||
ss.addfinalizer(fin_module, mod)
|
||||
ss.addfinalizer(fin_func, item)
|
||||
with pytest.raises(Exception, match="oops1"):
|
||||
|
|
Loading…
Reference in New Issue