Split Session._collection_node_cache to 3 mutually exclusive parts

Previously, this cache was used with 3 different and mutually exclusive
key-type -> value-type combinations. Mypy can't properly type this. It's
also quite confusing.

Split to 3 different dicts instead.
This commit is contained in:
Ran Benita 2020-01-24 11:43:14 +02:00
parent a76bc64c54
commit f3967333a1
1 changed files with 28 additions and 14 deletions

View File

@ -8,6 +8,7 @@ import sys
from typing import Dict
from typing import FrozenSet
from typing import List
from typing import Sequence
from typing import Tuple
import attr
@ -21,13 +22,15 @@ from _pytest.config import directory_arg
from _pytest.config import hookimpl
from _pytest.config import UsageError
from _pytest.fixtures import FixtureManager
from _pytest.nodes import Node
from _pytest.outcomes import exit
from _pytest.reports import CollectReport
from _pytest.runner import collect_one_node
from _pytest.runner import SetupState
if TYPE_CHECKING:
from typing import Type
from _pytest.python import Package
@ -407,7 +410,16 @@ class Session(nodes.FSCollector):
self._initialpaths = frozenset() # type: FrozenSet[py.path.local]
# Keep track of any collected nodes in here, so we don't duplicate fixtures
self._collection_node_cache = {} # type: Dict[str, List[Node]]
self._collection_node_cache1 = (
{}
) # type: Dict[py.path.local, Sequence[nodes.Collector]]
self._collection_node_cache2 = (
{}
) # type: Dict[Tuple[Type[nodes.Collector], py.path.local], nodes.Collector]
self._collection_node_cache3 = (
{}
) # type: Dict[Tuple[Type[nodes.Collector], str], CollectReport]
# Dirnames of pkgs with dunder-init files.
self._collection_pkg_roots = {} # type: Dict[py.path.local, Package]
@ -525,7 +537,9 @@ class Session(nodes.FSCollector):
self._notfound.append((report_arg, sys.exc_info()[1]))
self.trace.root.indent -= 1
self._collection_node_cache.clear()
self._collection_node_cache1.clear()
self._collection_node_cache2.clear()
self._collection_node_cache3.clear()
self._collection_pkg_roots.clear()
def _collect(self, argpath, names):
@ -543,13 +557,13 @@ class Session(nodes.FSCollector):
if parent.isdir():
pkginit = parent.join("__init__.py")
if pkginit.isfile():
if pkginit not in self._collection_node_cache:
if pkginit not in self._collection_node_cache1:
col = self._collectfile(pkginit, handle_dupes=False)
if col:
if isinstance(col[0], Package):
self._collection_pkg_roots[parent] = col[0]
# always store a list in the cache, matchnodes expects it
self._collection_node_cache[col[0].fspath] = [col[0]]
self._collection_node_cache1[col[0].fspath] = [col[0]]
# If it's a directory argument, recurse and look for any Subpackages.
# Let the Package collector deal with subnodes, don't collect here.
@ -576,21 +590,21 @@ class Session(nodes.FSCollector):
for x in self._collectfile(path):
key = (type(x), x.fspath)
if key in self._collection_node_cache:
yield self._collection_node_cache[key]
if key in self._collection_node_cache2:
yield self._collection_node_cache2[key]
else:
self._collection_node_cache[key] = x
self._collection_node_cache2[key] = x
yield x
else:
assert argpath.check(file=1)
if argpath in self._collection_node_cache:
col = self._collection_node_cache[argpath]
if argpath in self._collection_node_cache1:
col = self._collection_node_cache1[argpath]
else:
collect_root = self._collection_pkg_roots.get(argpath.dirname, self)
col = collect_root._collectfile(argpath, handle_dupes=False)
if col:
self._collection_node_cache[argpath] = col
self._collection_node_cache1[argpath] = col
m = self.matchnodes(col, names)
# 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__
@ -703,11 +717,11 @@ class Session(nodes.FSCollector):
continue
assert isinstance(node, nodes.Collector)
key = (type(node), node.nodeid)
if key in self._collection_node_cache:
rep = self._collection_node_cache[key]
if key in self._collection_node_cache3:
rep = self._collection_node_cache3[key]
else:
rep = collect_one_node(node)
self._collection_node_cache[key] = rep
self._collection_node_cache3[key] = rep
if rep.passed:
has_matched = False
for x in rep.result: