Clear collection caches after collection is done
Also rename the involved variables to convey its intent better and add type hints
This commit is contained in:
		
							parent
							
								
									2f0d0fb349
								
							
						
					
					
						commit
						7b1e3d1c9a
					
				| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -381,7 +389,7 @@ class Session(nodes.FSCollector):
 | 
				
			||||||
    _setupstate = None  # type: SetupState
 | 
					    _setupstate = None  # type: SetupState
 | 
				
			||||||
    _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=""
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -392,14 +400,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")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -511,6 +521,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
 | 
				
			||||||
| 
						 | 
					@ -530,13 +542,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.
 | 
				
			||||||
| 
						 | 
					@ -556,28 +568,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__
 | 
				
			||||||
| 
						 | 
					@ -690,11 +702,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