Skip to content

Commit aa475d0

Browse files
committed
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.
1 parent e17f5fa commit aa475d0

File tree

1 file changed

+29
-15
lines changed

1 file changed

+29
-15
lines changed

src/_pytest/main.py

+29-15
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import sys
88
from typing import Dict
99
from typing import FrozenSet
10-
from typing import List
10+
from typing import Sequence
11+
from typing import Tuple
1112

1213
import attr
1314
import py
@@ -19,13 +20,15 @@
1920
from _pytest.config import hookimpl
2021
from _pytest.config import UsageError
2122
from _pytest.fixtures import FixtureManager
22-
from _pytest.nodes import Node
2323
from _pytest.outcomes import exit
24+
from _pytest.reports import CollectReport
2425
from _pytest.runner import collect_one_node
2526
from _pytest.runner import SetupState
2627

2728

2829
if TYPE_CHECKING:
30+
from typing import Type
31+
2932
from _pytest.python import Package
3033

3134

@@ -405,7 +408,16 @@ def __init__(self, config) -> None:
405408
self._initialpaths = frozenset() # type: FrozenSet[py.path.local]
406409

407410
# Keep track of any collected nodes in here, so we don't duplicate fixtures
408-
self._collection_node_cache = {} # type: Dict[str, List[Node]]
411+
self._collection_node_cache1 = (
412+
{}
413+
) # type: Dict[py.path.local, Sequence[nodes.Collector]]
414+
self._collection_node_cache2 = (
415+
{}
416+
) # type: Dict[Tuple[Type[nodes.Collector], py.path.local], nodes.Collector]
417+
self._collection_node_cache3 = (
418+
{}
419+
) # type: Dict[Tuple[Type[nodes.Collector], str], CollectReport]
420+
409421
# Dirnames of pkgs with dunder-init files.
410422
self._collection_pkg_roots = {} # type: Dict[py.path.local, Package]
411423

@@ -523,7 +535,9 @@ def collect(self):
523535
self._notfound.append((report_arg, sys.exc_info()[1]))
524536

525537
self.trace.root.indent -= 1
526-
self._collection_node_cache.clear()
538+
self._collection_node_cache1.clear()
539+
self._collection_node_cache2.clear()
540+
self._collection_node_cache3.clear()
527541
self._collection_pkg_roots.clear()
528542

529543
def _collect(self, arg):
@@ -544,13 +558,13 @@ def _collect(self, arg):
544558
if parent.isdir():
545559
pkginit = parent.join("__init__.py")
546560
if pkginit.isfile():
547-
if pkginit not in self._collection_node_cache:
561+
if pkginit not in self._collection_node_cache1:
548562
col = self._collectfile(pkginit, handle_dupes=False)
549563
if col:
550564
if isinstance(col[0], Package):
551565
self._collection_pkg_roots[parent] = col[0]
552566
# always store a list in the cache, matchnodes expects it
553-
self._collection_node_cache[col[0].fspath] = [col[0]]
567+
self._collection_node_cache1[col[0].fspath] = [col[0]]
554568

555569
# If it's a directory argument, recurse and look for any Subpackages.
556570
# Let the Package collector deal with subnodes, don't collect here.
@@ -577,21 +591,21 @@ def _collect(self, arg):
577591

578592
for x in self._collectfile(path):
579593
key = (type(x), x.fspath)
580-
if key in self._collection_node_cache:
581-
yield self._collection_node_cache[key]
594+
if key in self._collection_node_cache2:
595+
yield self._collection_node_cache2[key]
582596
else:
583-
self._collection_node_cache[key] = x
597+
self._collection_node_cache2[key] = x
584598
yield x
585599
else:
586600
assert argpath.check(file=1)
587601

588-
if argpath in self._collection_node_cache:
589-
col = self._collection_node_cache[argpath]
602+
if argpath in self._collection_node_cache1:
603+
col = self._collection_node_cache1[argpath]
590604
else:
591605
collect_root = self._collection_pkg_roots.get(argpath.dirname, self)
592606
col = collect_root._collectfile(argpath, handle_dupes=False)
593607
if col:
594-
self._collection_node_cache[argpath] = col
608+
self._collection_node_cache1[argpath] = col
595609
m = self.matchnodes(col, names)
596610
# If __init__.py was the only file requested, then the matched node will be
597611
# the corresponding Package, and the first yielded item will be the __init__
@@ -704,11 +718,11 @@ def _matchnodes(self, matching, names):
704718
continue
705719
assert isinstance(node, nodes.Collector)
706720
key = (type(node), node.nodeid)
707-
if key in self._collection_node_cache:
708-
rep = self._collection_node_cache[key]
721+
if key in self._collection_node_cache3:
722+
rep = self._collection_node_cache3[key]
709723
else:
710724
rep = collect_one_node(node)
711-
self._collection_node_cache[key] = rep
725+
self._collection_node_cache3[key] = rep
712726
if rep.passed:
713727
has_matched = False
714728
for x in rep.result:

0 commit comments

Comments
 (0)