add special cases for 'request' and direct parametrization arguments
This commit is contained in:
parent
3f91fb839d
commit
e9bb86b6a9
|
@ -366,6 +366,7 @@ class FuncFixtureInfo2:
|
||||||
# - check which sort/sorted calls need to be reversed by default.
|
# - check which sort/sorted calls need to be reversed by default.
|
||||||
# - maybe replace Tuple[str, int] by a NamedTuple?
|
# - maybe replace Tuple[str, int] by a NamedTuple?
|
||||||
# - make this a frozen dataclass again? this would make clone more difficult to implement!
|
# - make this a frozen dataclass again? this would make clone more difficult to implement!
|
||||||
|
# - special case 'request' and nodes without fixture definitions in fixturedef_closure
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
"argnames",
|
"argnames",
|
||||||
"initialnames",
|
"initialnames",
|
||||||
|
@ -413,6 +414,7 @@ class FuncFixtureInfo2:
|
||||||
self._outgoing = defaultdict(defaultdict)
|
self._outgoing = defaultdict(defaultdict)
|
||||||
self._incoming = defaultdict(defaultdict)
|
self._incoming = defaultdict(defaultdict)
|
||||||
self._reuse = set()
|
self._reuse = set()
|
||||||
|
self._closure_store = []
|
||||||
|
|
||||||
def clone(self) -> "FuncFixtureInfo2":
|
def clone(self) -> "FuncFixtureInfo2":
|
||||||
clone = FuncFixtureInfo2(self.argnames, copy.copy(self.initialnames))
|
clone = FuncFixtureInfo2(self.argnames, copy.copy(self.initialnames))
|
||||||
|
@ -448,7 +450,7 @@ class FuncFixtureInfo2:
|
||||||
|
|
||||||
def name_idx_closure(self, reverse: bool = False) -> Sequence[Tuple[str, int]]:
|
def name_idx_closure(self, reverse: bool = False) -> Sequence[Tuple[str, int]]:
|
||||||
# closure in topological sort order / scope is not honored
|
# closure in topological sort order / scope is not honored
|
||||||
return sorted(self._rank, key=self._rank.__getitem__)
|
return sorted(self._rank, key=self._rank.__getitem__, reverse=reverse)
|
||||||
|
|
||||||
def fixturedef_closure(self, reverse: bool = False) -> Sequence["FixtureDef[Any]"]:
|
def fixturedef_closure(self, reverse: bool = False) -> Sequence["FixtureDef[Any]"]:
|
||||||
# closure in topogical sort order and proper scope order
|
# closure in topogical sort order and proper scope order
|
||||||
|
@ -457,6 +459,7 @@ class FuncFixtureInfo2:
|
||||||
return sorted(
|
return sorted(
|
||||||
(self.name2fixturedefs[name][idx] for name, idx in self.name_idx_closure()),
|
(self.name2fixturedefs[name][idx] for name, idx in self.name_idx_closure()),
|
||||||
key=lambda d: d._scope,
|
key=lambda d: d._scope,
|
||||||
|
reverse=reverse,
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_node(self, node: Tuple[str, int]):
|
def add_node(self, node: Tuple[str, int]):
|
||||||
|
@ -540,7 +543,9 @@ class FuncFixtureInfo2:
|
||||||
for node in {
|
for node in {
|
||||||
node
|
node
|
||||||
for node in self._rank
|
for node in self._rank
|
||||||
if node not in self._outgoing and node not in self._incoming
|
if node not in self._outgoing
|
||||||
|
and node not in self._incoming
|
||||||
|
and node not in roots
|
||||||
}:
|
}:
|
||||||
self.remove_fixture(node)
|
self.remove_fixture(node)
|
||||||
|
|
||||||
|
@ -1738,12 +1743,11 @@ class FixtureManager:
|
||||||
def getfixtureinfo2(
|
def getfixtureinfo2(
|
||||||
self,
|
self,
|
||||||
node: nodes.Item,
|
node: nodes.Item,
|
||||||
func: Callable[..., object],
|
func: Optional[Callable[..., object]],
|
||||||
cls: Optional[type],
|
cls: Optional[type],
|
||||||
funcargs: bool = True,
|
|
||||||
) -> FuncFixtureInfo2:
|
) -> FuncFixtureInfo2:
|
||||||
"""See above"""
|
"""See above"""
|
||||||
if funcargs and not getattr(node, "nofuncargs", False):
|
if func is not None and not getattr(node, "nofuncargs", False):
|
||||||
argnames = getfuncargnames(func, name=node.name, cls=cls)
|
argnames = getfuncargnames(func, name=node.name, cls=cls)
|
||||||
else:
|
else:
|
||||||
argnames = ()
|
argnames = ()
|
||||||
|
@ -1846,7 +1850,7 @@ class FixtureManager:
|
||||||
self,
|
self,
|
||||||
info: FuncFixtureInfo2,
|
info: FuncFixtureInfo2,
|
||||||
nodeid: str,
|
nodeid: str,
|
||||||
ignore: Collection[str],
|
ignore_args: Collection[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
# TODO:
|
# TODO:
|
||||||
# - reword last sentence
|
# - reword last sentence
|
||||||
|
@ -1864,9 +1868,9 @@ class FixtureManager:
|
||||||
iter_stack: List[Iterator[str]] = [iter(info.initialnames)]
|
iter_stack: List[Iterator[str]] = [iter(info.initialnames)]
|
||||||
parent_stack: List[Tuple[str, int]] = []
|
parent_stack: List[Tuple[str, int]] = []
|
||||||
|
|
||||||
def retrieve(name: str) -> Sequence[FixtureDef[Any]] | None:
|
def retrieve(name: str) -> Optional[Sequence[FixtureDef[Any]]]:
|
||||||
try:
|
try:
|
||||||
return cache.get(name, None)
|
return cache[name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
defs = self.getfixturedefs(name, nodeid)
|
defs = self.getfixturedefs(name, nodeid)
|
||||||
if defs:
|
if defs:
|
||||||
|
@ -1875,49 +1879,51 @@ class FixtureManager:
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def push_onto_stack(node: Tuple[str, int], argnames: Sequence[str]):
|
||||||
|
if node not in parent_stack:
|
||||||
|
parent_stack.append(node)
|
||||||
|
iter_stack.append(iter(argnames))
|
||||||
|
|
||||||
while iter_stack:
|
while iter_stack:
|
||||||
arg = next(iter_stack[-1], None)
|
arg = next(iter_stack[-1], None)
|
||||||
if arg:
|
if arg:
|
||||||
if arg in ignore:
|
if arg == "request" or arg in ignore_args:
|
||||||
continue
|
# do not retrive definitions because they either to not exist
|
||||||
defs = retrieve(arg)
|
# or are replaced during parametrization.
|
||||||
if not defs:
|
if parent_stack:
|
||||||
# for now continue if no definitions are found
|
with suppress(DuplicateDependency):
|
||||||
# this should be guarded against by giving appropriate ignores
|
info.add_dependency(parent_stack[-1], (arg, -1))
|
||||||
continue
|
|
||||||
if parent_stack:
|
|
||||||
parent = parent_stack[-1]
|
|
||||||
# entry unconditionally exists at this point
|
|
||||||
parent_scope = cast(Sequence[FixtureDef[Any]], retrieve(parent[0]))[
|
|
||||||
parent[1]
|
|
||||||
]._scope
|
|
||||||
for i in range(-1, -len(defs) - 1, -1):
|
|
||||||
try:
|
|
||||||
info.add_dependency(parent, (arg, i))
|
|
||||||
except CyclicDependency:
|
|
||||||
continue
|
|
||||||
except DuplicateDependency:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if defs[i]._scope < parent_scope:
|
|
||||||
info.remove_dependency(parent, (arg, i))
|
|
||||||
raise Exception("Scope violation: ...")
|
|
||||||
# check if the fixture is already in the stack to bound
|
|
||||||
# the stack growth.
|
|
||||||
# this check is not a sufficient condition for termination
|
|
||||||
# of the algorithm.
|
|
||||||
if (arg, i) not in parent_stack:
|
|
||||||
parent_stack.append((arg, i))
|
|
||||||
iter_stack.append(iter(defs[i].argnames))
|
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
raise Exception("Cycle Detected: ...")
|
info.add_node((arg, -1))
|
||||||
else:
|
else:
|
||||||
parent_stack.append((arg, -1))
|
defs = retrieve(arg)
|
||||||
iter_stack.append(iter(defs[-1].argnames))
|
if not defs:
|
||||||
# make sure the initalnames are actually inserted even if they
|
# for now just skip if no definitions are found
|
||||||
# have no dependencies
|
continue
|
||||||
info.add_node((arg, -1))
|
if parent_stack:
|
||||||
|
parent = parent_stack[-1]
|
||||||
|
# entry unconditionally exists at this point
|
||||||
|
parent_scope = cast(
|
||||||
|
Sequence[FixtureDef[Any]], retrieve(parent[0])
|
||||||
|
)[parent[1]]._scope
|
||||||
|
for i in range(-1, -len(defs) - 1, -1):
|
||||||
|
try:
|
||||||
|
info.add_dependency(parent, (arg, i))
|
||||||
|
except CyclicDependency:
|
||||||
|
continue
|
||||||
|
except DuplicateDependency:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if defs[i]._scope < parent_scope:
|
||||||
|
info.remove_dependency(parent, (arg, i))
|
||||||
|
raise Exception("Scope violation: ...")
|
||||||
|
push_onto_stack((arg, i), defs[i].argnames)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise Exception("Cycle Detected: ...")
|
||||||
|
else:
|
||||||
|
push_onto_stack((arg, -1), defs[-1].argnames)
|
||||||
|
info.add_node((arg, -1))
|
||||||
else:
|
else:
|
||||||
# remove the exhausted iterator and backtrack
|
# remove the exhausted iterator and backtrack
|
||||||
iter_stack.pop()
|
iter_stack.pop()
|
||||||
|
|
Loading…
Reference in New Issue