Skip to content

Commit c225618

Browse files
committed
main: make matchnodes non-recursive
It's a little more sane this way.
1 parent 841521f commit c225618

File tree

1 file changed

+35
-33
lines changed

1 file changed

+35
-33
lines changed

src/_pytest/main.py

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -747,42 +747,44 @@ def matchnodes(
747747
matching: Sequence[Union[nodes.Item, nodes.Collector]],
748748
names: Sequence[str],
749749
) -> Sequence[Union[nodes.Item, nodes.Collector]]:
750-
self.trace("matchnodes", matching, names)
751-
self.trace.root.indent += 1
752-
753750
result = []
754-
for node in matching:
755-
if not names:
756-
result.append(node)
757-
continue
758-
if not isinstance(node, nodes.Collector):
759-
continue
760-
key = (type(node), node.nodeid)
761-
if key in self._collection_node_cache3:
762-
rep = self._collection_node_cache3[key]
763-
else:
764-
rep = collect_one_node(node)
765-
self._collection_node_cache3[key] = rep
766-
if rep.passed:
767-
submatching = []
768-
for x in rep.result:
769-
# TODO: Remove parametrized workaround once collection structure contains parametrization.
770-
if x.name == names[0] or x.name.split("[")[0] == names[0]:
771-
submatching.append(x)
772-
if submatching:
773-
result.extend(self.matchnodes(submatching, names[1:]))
774-
# XXX Accept IDs that don't have "()" for class instances.
775-
elif len(rep.result) == 1 and rep.result[0].name == "()":
776-
result.extend(self.matchnodes(rep.result, names))
777-
else:
778-
# Report collection failures here to avoid failing to run some test
779-
# specified in the command line because the module could not be
780-
# imported (#134).
781-
node.ihook.pytest_collectreport(report=rep)
751+
work = [(matching, names)]
752+
while work:
753+
self.trace("matchnodes", matching, names)
754+
self.trace.root.indent += 1
782755

783-
self.trace("matchnodes finished -> ", len(result), "nodes")
784-
self.trace.root.indent -= 1
756+
matching, names = work.pop()
757+
for node in matching:
758+
if not names:
759+
result.append(node)
760+
continue
761+
if not isinstance(node, nodes.Collector):
762+
continue
763+
key = (type(node), node.nodeid)
764+
if key in self._collection_node_cache3:
765+
rep = self._collection_node_cache3[key]
766+
else:
767+
rep = collect_one_node(node)
768+
self._collection_node_cache3[key] = rep
769+
if rep.passed:
770+
submatching = []
771+
for x in rep.result:
772+
# TODO: Remove parametrized workaround once collection structure contains parametrization.
773+
if x.name == names[0] or x.name.split("[")[0] == names[0]:
774+
submatching.append(x)
775+
if submatching:
776+
work.append((submatching, names[1:]))
777+
# XXX Accept IDs that don't have "()" for class instances.
778+
elif len(rep.result) == 1 and rep.result[0].name == "()":
779+
work.append((rep.result, names))
780+
else:
781+
# Report collection failures here to avoid failing to run some test
782+
# specified in the command line because the module could not be
783+
# imported (#134).
784+
node.ihook.pytest_collectreport(report=rep)
785785

786+
self.trace("matchnodes finished -> ", len(result), "nodes")
787+
self.trace.root.indent -= 1
786788
return result
787789

788790
def genitems(

0 commit comments

Comments
 (0)