Merge pull request #11393 from pytest-dev/fixtures-tweaks
Fixtures tweaks
This commit is contained in:
commit
faa8f2ea08
|
@ -579,9 +579,11 @@ def _setup_fixtures(doctest_item: DoctestItem) -> TopRequest:
|
|||
|
||||
doctest_item.funcargs = {} # type: ignore[attr-defined]
|
||||
fm = doctest_item.session._fixturemanager
|
||||
doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
|
||||
fixtureinfo = fm.getfixtureinfo(
|
||||
node=doctest_item, func=func, cls=None, funcargs=False
|
||||
)
|
||||
doctest_item._fixtureinfo = fixtureinfo # type: ignore[attr-defined]
|
||||
doctest_item.fixturenames = fixtureinfo.names_closure # type: ignore[attr-defined]
|
||||
fixture_request = TopRequest(doctest_item, _ispytest=True) # type: ignore[arg-type]
|
||||
fixture_request._fillfixtures()
|
||||
return fixture_request
|
||||
|
|
|
@ -210,16 +210,14 @@ def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]:
|
|||
argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[FixtureArgKey, None]]] = {}
|
||||
items_by_argkey: Dict[Scope, Dict[FixtureArgKey, Deque[nodes.Item]]] = {}
|
||||
for scope in HIGH_SCOPES:
|
||||
d: Dict[nodes.Item, Dict[FixtureArgKey, None]] = {}
|
||||
argkeys_cache[scope] = d
|
||||
item_d: Dict[FixtureArgKey, Deque[nodes.Item]] = defaultdict(deque)
|
||||
items_by_argkey[scope] = item_d
|
||||
scoped_argkeys_cache = argkeys_cache[scope] = {}
|
||||
scoped_items_by_argkey = items_by_argkey[scope] = defaultdict(deque)
|
||||
for item in items:
|
||||
keys = dict.fromkeys(get_parametrized_fixture_keys(item, scope), None)
|
||||
if keys:
|
||||
d[item] = keys
|
||||
scoped_argkeys_cache[item] = keys
|
||||
for key in keys:
|
||||
item_d[key].append(item)
|
||||
scoped_items_by_argkey[key].append(item)
|
||||
items_dict = dict.fromkeys(items, None)
|
||||
return list(
|
||||
reorder_items_atscope(items_dict, argkeys_cache, items_by_argkey, Scope.Session)
|
||||
|
@ -407,7 +405,7 @@ class FixtureRequest(abc.ABC):
|
|||
@property
|
||||
def fixturenames(self) -> List[str]:
|
||||
"""Names of all active fixtures in this request."""
|
||||
result = list(self._pyfuncitem._fixtureinfo.names_closure)
|
||||
result = list(self._pyfuncitem.fixturenames)
|
||||
result.extend(set(self._fixture_defs).difference(result))
|
||||
return result
|
||||
|
||||
|
@ -687,8 +685,7 @@ class TopRequest(FixtureRequest):
|
|||
|
||||
def _fillfixtures(self) -> None:
|
||||
item = self._pyfuncitem
|
||||
fixturenames = getattr(item, "fixturenames", self.fixturenames)
|
||||
for argname in fixturenames:
|
||||
for argname in item.fixturenames:
|
||||
if argname not in item.funcargs:
|
||||
item.funcargs[argname] = self.getfixturevalue(argname)
|
||||
|
||||
|
@ -794,7 +791,10 @@ class SubRequest(FixtureRequest):
|
|||
# If the executing fixturedef was not explicitly requested in the argument list (via
|
||||
# getfixturevalue inside the fixture call) then ensure this fixture def will be finished
|
||||
# first.
|
||||
if fixturedef.argname not in self.fixturenames:
|
||||
if (
|
||||
fixturedef.argname not in self._fixture_defs
|
||||
and fixturedef.argname not in self._pyfuncitem.fixturenames
|
||||
):
|
||||
fixturedef.addfinalizer(
|
||||
functools.partial(self._fixturedef.finish, request=self)
|
||||
)
|
||||
|
|
|
@ -473,7 +473,9 @@ class PyCollector(PyobjMixin, nodes.Collector):
|
|||
clscol = self.getparent(Class)
|
||||
cls = clscol and clscol.obj or None
|
||||
|
||||
definition = FunctionDefinition.from_parent(self, name=name, callobj=funcobj)
|
||||
definition: FunctionDefinition = FunctionDefinition.from_parent(
|
||||
self, name=name, callobj=funcobj
|
||||
)
|
||||
fixtureinfo = definition._fixtureinfo
|
||||
|
||||
# pytest_generate_tests impls call metafunc.parametrize() which fills
|
||||
|
@ -1123,9 +1125,9 @@ class CallSpec2:
|
|||
# arg name -> arg index.
|
||||
indices: Dict[str, int] = dataclasses.field(default_factory=dict)
|
||||
# Used for sorting parametrized resources.
|
||||
_arg2scope: Dict[str, Scope] = dataclasses.field(default_factory=dict)
|
||||
_arg2scope: Mapping[str, Scope] = dataclasses.field(default_factory=dict)
|
||||
# Parts which will be added to the item's name in `[..]` separated by "-".
|
||||
_idlist: List[str] = dataclasses.field(default_factory=list)
|
||||
_idlist: Sequence[str] = dataclasses.field(default_factory=tuple)
|
||||
# Marks which will be applied to the item.
|
||||
marks: List[Mark] = dataclasses.field(default_factory=list)
|
||||
|
||||
|
@ -1141,7 +1143,7 @@ class CallSpec2:
|
|||
) -> "CallSpec2":
|
||||
params = self.params.copy()
|
||||
indices = self.indices.copy()
|
||||
arg2scope = self._arg2scope.copy()
|
||||
arg2scope = dict(self._arg2scope)
|
||||
for arg, val in zip(argnames, valset):
|
||||
if arg in params:
|
||||
raise ValueError(f"duplicate parametrization of {arg!r}")
|
||||
|
|
Loading…
Reference in New Issue