Skip to content

Commit 7b1e3d1

Browse files
committed
Clear collection caches after collection is done
Also rename the involved variables to convey its intent better and add type hints
1 parent 2f0d0fb commit 7b1e3d1

File tree

1 file changed

+32
-20
lines changed

1 file changed

+32
-20
lines changed

src/_pytest/main.py

+32-20
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,29 @@
66
import os
77
import sys
88
from typing import Dict
9+
from typing import FrozenSet
10+
from typing import List
911

1012
import attr
1113
import py
1214

1315
import _pytest._code
1416
from _pytest import nodes
17+
from _pytest.compat import TYPE_CHECKING
1518
from _pytest.config import directory_arg
1619
from _pytest.config import hookimpl
1720
from _pytest.config import UsageError
1821
from _pytest.fixtures import FixtureManager
22+
from _pytest.nodes import Node
1923
from _pytest.outcomes import exit
2024
from _pytest.runner import collect_one_node
2125
from _pytest.runner import SetupState
2226

2327

28+
if TYPE_CHECKING:
29+
from _pytest.python import Package
30+
31+
2432
class ExitCode(enum.IntEnum):
2533
"""
2634
.. versionadded:: 5.0
@@ -381,7 +389,7 @@ class Session(nodes.FSCollector):
381389
_setupstate = None # type: SetupState
382390
_fixturemanager = None # type: FixtureManager
383391

384-
def __init__(self, config):
392+
def __init__(self, config) -> None:
385393
nodes.FSCollector.__init__(
386394
self, config.rootdir, parent=None, config=config, session=self, nodeid=""
387395
)
@@ -392,14 +400,16 @@ def __init__(self, config):
392400
self.trace = config.trace.root.get("collection")
393401
self._norecursepatterns = config.getini("norecursedirs")
394402
self.startdir = config.invocation_dir
395-
self._initialpaths = frozenset()
403+
self._initialpaths = frozenset() # type: FrozenSet[py.path.local]
404+
396405
# Keep track of any collected nodes in here, so we don't duplicate fixtures
397-
self._node_cache = {}
406+
self._collection_node_cache = {} # type: Dict[str, List[Node]]
407+
# Dirnames of pkgs with dunder-init files.
408+
self._collection_pkg_roots = {} # type: Dict[py.path.local, Package]
409+
398410
self._bestrelpathcache = _bestrelpath_cache(
399411
config.rootdir
400412
) # type: Dict[str, str]
401-
# Dirnames of pkgs with dunder-init files.
402-
self._pkg_roots = {}
403413

404414
self.config.pluginmanager.register(self, name="session")
405415

@@ -511,6 +521,8 @@ def collect(self):
511521
self._notfound.append((report_arg, sys.exc_info()[1]))
512522

513523
self.trace.root.indent -= 1
524+
self._collection_node_cache.clear()
525+
self._collection_pkg_roots.clear()
514526

515527
def _collect(self, arg):
516528
from _pytest.python import Package
@@ -530,13 +542,13 @@ def _collect(self, arg):
530542
if parent.isdir():
531543
pkginit = parent.join("__init__.py")
532544
if pkginit.isfile():
533-
if pkginit not in self._node_cache:
545+
if pkginit not in self._collection_node_cache:
534546
col = self._collectfile(pkginit, handle_dupes=False)
535547
if col:
536548
if isinstance(col[0], Package):
537-
self._pkg_roots[parent] = col[0]
549+
self._collection_pkg_roots[parent] = col[0]
538550
# always store a list in the cache, matchnodes expects it
539-
self._node_cache[col[0].fspath] = [col[0]]
551+
self._collection_node_cache[col[0].fspath] = [col[0]]
540552

541553
# If it's a directory argument, recurse and look for any Subpackages.
542554
# Let the Package collector deal with subnodes, don't collect here.
@@ -556,28 +568,28 @@ def _collect(self, arg):
556568
for x in self._collectfile(pkginit):
557569
yield x
558570
if isinstance(x, Package):
559-
self._pkg_roots[dirpath] = x
560-
if dirpath in self._pkg_roots:
571+
self._collection_pkg_roots[dirpath] = x
572+
if dirpath in self._collection_pkg_roots:
561573
# Do not collect packages here.
562574
continue
563575

564576
for x in self._collectfile(path):
565577
key = (type(x), x.fspath)
566-
if key in self._node_cache:
567-
yield self._node_cache[key]
578+
if key in self._collection_node_cache:
579+
yield self._collection_node_cache[key]
568580
else:
569-
self._node_cache[key] = x
581+
self._collection_node_cache[key] = x
570582
yield x
571583
else:
572584
assert argpath.check(file=1)
573585

574-
if argpath in self._node_cache:
575-
col = self._node_cache[argpath]
586+
if argpath in self._collection_node_cache:
587+
col = self._collection_node_cache[argpath]
576588
else:
577-
collect_root = self._pkg_roots.get(argpath.dirname, self)
589+
collect_root = self._collection_pkg_roots.get(argpath.dirname, self)
578590
col = collect_root._collectfile(argpath, handle_dupes=False)
579591
if col:
580-
self._node_cache[argpath] = col
592+
self._collection_node_cache[argpath] = col
581593
m = self.matchnodes(col, names)
582594
# If __init__.py was the only file requested, then the matched node will be
583595
# the corresponding Package, and the first yielded item will be the __init__
@@ -690,11 +702,11 @@ def _matchnodes(self, matching, names):
690702
continue
691703
assert isinstance(node, nodes.Collector)
692704
key = (type(node), node.nodeid)
693-
if key in self._node_cache:
694-
rep = self._node_cache[key]
705+
if key in self._collection_node_cache:
706+
rep = self._collection_node_cache[key]
695707
else:
696708
rep = collect_one_node(node)
697-
self._node_cache[key] = rep
709+
self._collection_node_cache[key] = rep
698710
if rep.passed:
699711
has_matched = False
700712
for x in rep.result:

0 commit comments

Comments
 (0)