Merge pull request #6555 from bluetech/nodes-cache-split
Split Session._collection_node_cache to 3 mutually exclusive parts
This commit is contained in:
		
						commit
						e440b43258
					
				| 
						 | 
					@ -8,6 +8,7 @@ import sys
 | 
				
			||||||
from typing import Dict
 | 
					from typing import Dict
 | 
				
			||||||
from typing import FrozenSet
 | 
					from typing import FrozenSet
 | 
				
			||||||
from typing import List
 | 
					from typing import List
 | 
				
			||||||
 | 
					from typing import Sequence
 | 
				
			||||||
from typing import Tuple
 | 
					from typing import Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import attr
 | 
					import attr
 | 
				
			||||||
| 
						 | 
					@ -21,13 +22,15 @@ 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.reports import CollectReport
 | 
				
			||||||
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:
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
 | 
					    from typing import Type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from _pytest.python import Package
 | 
					    from _pytest.python import Package
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -407,7 +410,16 @@ class Session(nodes.FSCollector):
 | 
				
			||||||
        self._initialpaths = frozenset()  # type: FrozenSet[py.path.local]
 | 
					        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._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.
 | 
					        # Dirnames of pkgs with dunder-init files.
 | 
				
			||||||
        self._collection_pkg_roots = {}  # type: Dict[py.path.local, Package]
 | 
					        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._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_node_cache1.clear()
 | 
				
			||||||
 | 
					        self._collection_node_cache2.clear()
 | 
				
			||||||
 | 
					        self._collection_node_cache3.clear()
 | 
				
			||||||
        self._collection_pkg_roots.clear()
 | 
					        self._collection_pkg_roots.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _collect(self, argpath, names):
 | 
					    def _collect(self, argpath, names):
 | 
				
			||||||
| 
						 | 
					@ -543,13 +557,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._collection_node_cache:
 | 
					                        if pkginit not in self._collection_node_cache1:
 | 
				
			||||||
                            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._collection_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._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.
 | 
					        # 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.
 | 
				
			||||||
| 
						 | 
					@ -576,21 +590,21 @@ class Session(nodes.FSCollector):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                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._collection_node_cache:
 | 
					                    if key in self._collection_node_cache2:
 | 
				
			||||||
                        yield self._collection_node_cache[key]
 | 
					                        yield self._collection_node_cache2[key]
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        self._collection_node_cache[key] = x
 | 
					                        self._collection_node_cache2[key] = x
 | 
				
			||||||
                        yield x
 | 
					                        yield x
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            assert argpath.check(file=1)
 | 
					            assert argpath.check(file=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if argpath in self._collection_node_cache:
 | 
					            if argpath in self._collection_node_cache1:
 | 
				
			||||||
                col = self._collection_node_cache[argpath]
 | 
					                col = self._collection_node_cache1[argpath]
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                collect_root = self._collection_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._collection_node_cache[argpath] = col
 | 
					                    self._collection_node_cache1[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__
 | 
				
			||||||
| 
						 | 
					@ -703,11 +717,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._collection_node_cache:
 | 
					            if key in self._collection_node_cache3:
 | 
				
			||||||
                rep = self._collection_node_cache[key]
 | 
					                rep = self._collection_node_cache3[key]
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                rep = collect_one_node(node)
 | 
					                rep = collect_one_node(node)
 | 
				
			||||||
                self._collection_node_cache[key] = rep
 | 
					                self._collection_node_cache3[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