Clear node collection cache after collection is done (#6491)
Clear node collection cache after collection is done
This commit is contained in:
commit
e17f5fad14
|
@ -6,21 +6,29 @@ import importlib
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import FrozenSet
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
import py
|
import py
|
||||||
|
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
|
from _pytest.compat import TYPE_CHECKING
|
||||||
from _pytest.config import directory_arg
|
from _pytest.config import directory_arg
|
||||||
from _pytest.config import hookimpl
|
from _pytest.config import hookimpl
|
||||||
from _pytest.config import UsageError
|
from _pytest.config import UsageError
|
||||||
from _pytest.fixtures import FixtureManager
|
from _pytest.fixtures import FixtureManager
|
||||||
|
from _pytest.nodes import Node
|
||||||
from _pytest.outcomes import exit
|
from _pytest.outcomes import exit
|
||||||
from _pytest.runner import collect_one_node
|
from _pytest.runner import collect_one_node
|
||||||
from _pytest.runner import SetupState
|
from _pytest.runner import SetupState
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from _pytest.python import Package
|
||||||
|
|
||||||
|
|
||||||
class ExitCode(enum.IntEnum):
|
class ExitCode(enum.IntEnum):
|
||||||
"""
|
"""
|
||||||
.. versionadded:: 5.0
|
.. versionadded:: 5.0
|
||||||
|
@ -383,7 +391,7 @@ class Session(nodes.FSCollector):
|
||||||
# Set on the session by fixtures.pytest_sessionstart.
|
# Set on the session by fixtures.pytest_sessionstart.
|
||||||
_fixturemanager = None # type: FixtureManager
|
_fixturemanager = None # type: FixtureManager
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config) -> None:
|
||||||
nodes.FSCollector.__init__(
|
nodes.FSCollector.__init__(
|
||||||
self, config.rootdir, parent=None, config=config, session=self, nodeid=""
|
self, config.rootdir, parent=None, config=config, session=self, nodeid=""
|
||||||
)
|
)
|
||||||
|
@ -394,14 +402,16 @@ class Session(nodes.FSCollector):
|
||||||
self.trace = config.trace.root.get("collection")
|
self.trace = config.trace.root.get("collection")
|
||||||
self._norecursepatterns = config.getini("norecursedirs")
|
self._norecursepatterns = config.getini("norecursedirs")
|
||||||
self.startdir = config.invocation_dir
|
self.startdir = config.invocation_dir
|
||||||
self._initialpaths = frozenset()
|
self._initialpaths = frozenset() # type: FrozenSet[py.path.local]
|
||||||
|
|
||||||
# Keep track of any collected nodes in here, so we don't duplicate fixtures
|
# Keep track of any collected nodes in here, so we don't duplicate fixtures
|
||||||
self._node_cache = {}
|
self._collection_node_cache = {} # type: Dict[str, List[Node]]
|
||||||
|
# Dirnames of pkgs with dunder-init files.
|
||||||
|
self._collection_pkg_roots = {} # type: Dict[py.path.local, Package]
|
||||||
|
|
||||||
self._bestrelpathcache = _bestrelpath_cache(
|
self._bestrelpathcache = _bestrelpath_cache(
|
||||||
config.rootdir
|
config.rootdir
|
||||||
) # type: Dict[str, str]
|
) # type: Dict[str, str]
|
||||||
# Dirnames of pkgs with dunder-init files.
|
|
||||||
self._pkg_roots = {}
|
|
||||||
|
|
||||||
self.config.pluginmanager.register(self, name="session")
|
self.config.pluginmanager.register(self, name="session")
|
||||||
|
|
||||||
|
@ -513,6 +523,8 @@ class Session(nodes.FSCollector):
|
||||||
self._notfound.append((report_arg, sys.exc_info()[1]))
|
self._notfound.append((report_arg, sys.exc_info()[1]))
|
||||||
|
|
||||||
self.trace.root.indent -= 1
|
self.trace.root.indent -= 1
|
||||||
|
self._collection_node_cache.clear()
|
||||||
|
self._collection_pkg_roots.clear()
|
||||||
|
|
||||||
def _collect(self, arg):
|
def _collect(self, arg):
|
||||||
from _pytest.python import Package
|
from _pytest.python import Package
|
||||||
|
@ -532,13 +544,13 @@ class Session(nodes.FSCollector):
|
||||||
if parent.isdir():
|
if parent.isdir():
|
||||||
pkginit = parent.join("__init__.py")
|
pkginit = parent.join("__init__.py")
|
||||||
if pkginit.isfile():
|
if pkginit.isfile():
|
||||||
if pkginit not in self._node_cache:
|
if pkginit not in self._collection_node_cache:
|
||||||
col = self._collectfile(pkginit, handle_dupes=False)
|
col = self._collectfile(pkginit, handle_dupes=False)
|
||||||
if col:
|
if col:
|
||||||
if isinstance(col[0], Package):
|
if isinstance(col[0], Package):
|
||||||
self._pkg_roots[parent] = col[0]
|
self._collection_pkg_roots[parent] = col[0]
|
||||||
# always store a list in the cache, matchnodes expects it
|
# always store a list in the cache, matchnodes expects it
|
||||||
self._node_cache[col[0].fspath] = [col[0]]
|
self._collection_node_cache[col[0].fspath] = [col[0]]
|
||||||
|
|
||||||
# If it's a directory argument, recurse and look for any Subpackages.
|
# If it's a directory argument, recurse and look for any Subpackages.
|
||||||
# Let the Package collector deal with subnodes, don't collect here.
|
# Let the Package collector deal with subnodes, don't collect here.
|
||||||
|
@ -558,28 +570,28 @@ class Session(nodes.FSCollector):
|
||||||
for x in self._collectfile(pkginit):
|
for x in self._collectfile(pkginit):
|
||||||
yield x
|
yield x
|
||||||
if isinstance(x, Package):
|
if isinstance(x, Package):
|
||||||
self._pkg_roots[dirpath] = x
|
self._collection_pkg_roots[dirpath] = x
|
||||||
if dirpath in self._pkg_roots:
|
if dirpath in self._collection_pkg_roots:
|
||||||
# Do not collect packages here.
|
# Do not collect packages here.
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for x in self._collectfile(path):
|
for x in self._collectfile(path):
|
||||||
key = (type(x), x.fspath)
|
key = (type(x), x.fspath)
|
||||||
if key in self._node_cache:
|
if key in self._collection_node_cache:
|
||||||
yield self._node_cache[key]
|
yield self._collection_node_cache[key]
|
||||||
else:
|
else:
|
||||||
self._node_cache[key] = x
|
self._collection_node_cache[key] = x
|
||||||
yield x
|
yield x
|
||||||
else:
|
else:
|
||||||
assert argpath.check(file=1)
|
assert argpath.check(file=1)
|
||||||
|
|
||||||
if argpath in self._node_cache:
|
if argpath in self._collection_node_cache:
|
||||||
col = self._node_cache[argpath]
|
col = self._collection_node_cache[argpath]
|
||||||
else:
|
else:
|
||||||
collect_root = self._pkg_roots.get(argpath.dirname, self)
|
collect_root = self._collection_pkg_roots.get(argpath.dirname, self)
|
||||||
col = collect_root._collectfile(argpath, handle_dupes=False)
|
col = collect_root._collectfile(argpath, handle_dupes=False)
|
||||||
if col:
|
if col:
|
||||||
self._node_cache[argpath] = col
|
self._collection_node_cache[argpath] = col
|
||||||
m = self.matchnodes(col, names)
|
m = self.matchnodes(col, names)
|
||||||
# If __init__.py was the only file requested, then the matched node will be
|
# 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__
|
# the corresponding Package, and the first yielded item will be the __init__
|
||||||
|
@ -692,11 +704,11 @@ class Session(nodes.FSCollector):
|
||||||
continue
|
continue
|
||||||
assert isinstance(node, nodes.Collector)
|
assert isinstance(node, nodes.Collector)
|
||||||
key = (type(node), node.nodeid)
|
key = (type(node), node.nodeid)
|
||||||
if key in self._node_cache:
|
if key in self._collection_node_cache:
|
||||||
rep = self._node_cache[key]
|
rep = self._collection_node_cache[key]
|
||||||
else:
|
else:
|
||||||
rep = collect_one_node(node)
|
rep = collect_one_node(node)
|
||||||
self._node_cache[key] = rep
|
self._collection_node_cache[key] = rep
|
||||||
if rep.passed:
|
if rep.passed:
|
||||||
has_matched = False
|
has_matched = False
|
||||||
for x in rep.result:
|
for x in rep.result:
|
||||||
|
|
Loading…
Reference in New Issue