Merge pull request #11393 from pytest-dev/fixtures-tweaks

Fixtures tweaks
This commit is contained in:
Ran Benita 2023-09-06 09:15:28 +03:00 committed by GitHub
commit faa8f2ea08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 15 deletions

View File

@ -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

View File

@ -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)
)

View File

@ -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}")