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