main: inline matchnodes() into collect()

Now all of the logic is in one place and may be simplified and
refactored in more sensible way.
This commit is contained in:
Ran Benita 2020-08-22 11:35:54 +03:00
parent d0e8b71404
commit c867452488
1 changed files with 51 additions and 50 deletions

View File

@ -707,8 +707,53 @@ class Session(nodes.FSCollector):
col = collect_root._collectfile(argpath, handle_dupes=False) col = collect_root._collectfile(argpath, handle_dupes=False)
if col: if col:
self._collection_node_cache1[argpath] = col self._collection_node_cache1[argpath] = col
m = self.matchnodes(col, names)
if not m: matching = []
work = [
(col, names)
] # type: List[Tuple[Sequence[Union[nodes.Item, nodes.Collector]], Sequence[str]]]
while work:
self.trace("matchnodes", col, names)
self.trace.root.indent += 1
matchnodes, matchnames = work.pop()
for node in matchnodes:
if not matchnames:
matching.append(node)
continue
if not isinstance(node, nodes.Collector):
continue
key = (type(node), node.nodeid)
if key in self._collection_matchnodes_cache:
rep = self._collection_matchnodes_cache[key]
else:
rep = collect_one_node(node)
self._collection_matchnodes_cache[key] = rep
if rep.passed:
submatchnodes = []
for r in rep.result:
# TODO: Remove parametrized workaround once collection structure contains
# parametrization.
if (
r.name == matchnames[0]
or r.name.split("[")[0] == matchnames[0]
):
submatchnodes.append(r)
if submatchnodes:
work.append((submatchnodes, matchnames[1:]))
# XXX Accept IDs that don't have "()" for class instances.
elif len(rep.result) == 1 and rep.result[0].name == "()":
work.append((rep.result, matchnames))
else:
# Report collection failures here to avoid failing to run some test
# specified in the command line because the module could not be
# imported (#134).
node.ihook.pytest_collectreport(report=rep)
self.trace("matchnodes finished -> ", len(matching), "nodes")
self.trace.root.indent -= 1
if not matching:
report_arg = "::".join((str(argpath), *names)) report_arg = "::".join((str(argpath), *names))
self._notfound.append((report_arg, col)) self._notfound.append((report_arg, col))
continue continue
@ -718,16 +763,17 @@ class Session(nodes.FSCollector):
# Module itself, so just use that. If this special case isn't taken, then all # Module itself, so just use that. If this special case isn't taken, then all
# the files in the package will be yielded. # the files in the package will be yielded.
if argpath.basename == "__init__.py": if argpath.basename == "__init__.py":
assert isinstance(m[0], nodes.Collector) assert isinstance(matching[0], nodes.Collector)
try: try:
yield next(iter(m[0].collect())) yield next(iter(matching[0].collect()))
except StopIteration: except StopIteration:
# The package collects nothing with only an __init__.py # The package collects nothing with only an __init__.py
# file in it, which gets ignored by the default # file in it, which gets ignored by the default
# "python_files" option. # "python_files" option.
pass pass
continue continue
yield from m
yield from matching
self.trace.root.indent -= 1 self.trace.root.indent -= 1
self._collection_node_cache1.clear() self._collection_node_cache1.clear()
@ -735,51 +781,6 @@ class Session(nodes.FSCollector):
self._collection_matchnodes_cache.clear() self._collection_matchnodes_cache.clear()
self._collection_pkg_roots.clear() self._collection_pkg_roots.clear()
def matchnodes(
self,
matching: Sequence[Union[nodes.Item, nodes.Collector]],
names: Sequence[str],
) -> Sequence[Union[nodes.Item, nodes.Collector]]:
result = []
work = [(matching, names)]
while work:
self.trace("matchnodes", matching, names)
self.trace.root.indent += 1
matching, names = work.pop()
for node in matching:
if not names:
result.append(node)
continue
if not isinstance(node, nodes.Collector):
continue
key = (type(node), node.nodeid)
if key in self._collection_matchnodes_cache:
rep = self._collection_matchnodes_cache[key]
else:
rep = collect_one_node(node)
self._collection_matchnodes_cache[key] = rep
if rep.passed:
submatching = []
for x in rep.result:
# TODO: Remove parametrized workaround once collection structure contains parametrization.
if x.name == names[0] or x.name.split("[")[0] == names[0]:
submatching.append(x)
if submatching:
work.append((submatching, names[1:]))
# XXX Accept IDs that don't have "()" for class instances.
elif len(rep.result) == 1 and rep.result[0].name == "()":
work.append((rep.result, names))
else:
# Report collection failures here to avoid failing to run some test
# specified in the command line because the module could not be
# imported (#134).
node.ihook.pytest_collectreport(report=rep)
self.trace("matchnodes finished -> ", len(result), "nodes")
self.trace.root.indent -= 1
return result
def genitems( def genitems(
self, node: Union[nodes.Item, nodes.Collector] self, node: Union[nodes.Item, nodes.Collector]
) -> Iterator[nodes.Item]: ) -> Iterator[nodes.Item]: