Skip to content

Commit 470ea50

Browse files
committed
fixtures: fix quadratic behavior in the number of autouse fixtures
It turns out all autouse fixtures are kept in a global list, and thinned out for a particular node using a linear scan of the entire list each time. Change the list to a dict, and only take the nodes we need.
1 parent d6becfa commit 470ea50

File tree

2 files changed

+9
-7
lines changed

2 files changed

+9
-7
lines changed

changelog/4824.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed quadratic behavior and improved performance of collection of items using autouse fixtures and xunit fixtures.

src/_pytest/fixtures.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,9 +1412,10 @@ def __init__(self, session: "Session") -> None:
14121412
self.config: Config = session.config
14131413
self._arg2fixturedefs: Dict[str, List[FixtureDef[Any]]] = {}
14141414
self._holderobjseen: Set[object] = set()
1415-
self._nodeid_and_autousenames: List[Tuple[str, List[str]]] = [
1416-
("", self.config.getini("usefixtures"))
1417-
]
1415+
# A mapping from a nodeid to a list of autouse fixtures it defines.
1416+
self._nodeid_autousenames: Dict[str, List[str]] = {
1417+
"": self.config.getini("usefixtures"),
1418+
}
14181419
session.config.pluginmanager.register(self, "funcmanage")
14191420

14201421
def _get_direct_parametrize_args(self, node: nodes.Node) -> List[str]:
@@ -1478,9 +1479,9 @@ def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None:
14781479

14791480
def _getautousenames(self, nodeid: str) -> Iterator[str]:
14801481
"""Return the names of autouse fixtures applicable to nodeid."""
1481-
parentnodeids = set(nodes.iterparentnodeids(nodeid))
1482-
for baseid, basenames in self._nodeid_and_autousenames:
1483-
if baseid in parentnodeids:
1482+
for parentnodeid in nodes.iterparentnodeids(nodeid):
1483+
basenames = self._nodeid_autousenames.get(parentnodeid)
1484+
if basenames:
14841485
yield from basenames
14851486

14861487
def getfixtureclosure(
@@ -1642,7 +1643,7 @@ def parsefactories(
16421643
autousenames.append(name)
16431644

16441645
if autousenames:
1645-
self._nodeid_and_autousenames.append((nodeid or "", autousenames))
1646+
self._nodeid_autousenames.setdefault(nodeid or "", []).extend(autousenames)
16461647

16471648
def getfixturedefs(
16481649
self, argname: str, nodeid: str

0 commit comments

Comments
 (0)