From 6639d6c7d86eef06331f3a29df73b0b5bd7de9a4 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Tue, 25 Jan 2022 16:21:44 +0200 Subject: [PATCH] Merge pull request #9532 from bluetech/getdir-cache config: avoid stat storm in _getconftestmodules (cherry picked from commit 5c69eced6cb3b844ab5a25e4e45d1c23bb1ebab2) Conflicts: src/_pytest/config/__init__.py --- src/_pytest/config/__init__.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 0cb900913..604b203d5 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -331,6 +331,14 @@ def _prepareconfig( raise +def _get_directory(path: Path) -> Path: + """Get the directory of a path - itself if already a directory.""" + if path.is_file(): + return path.parent + else: + return path + + @final class PytestPluginManager(PluginManager): """A :py:class:`pluggy.PluginManager ` with @@ -353,6 +361,12 @@ class PytestPluginManager(PluginManager): self._conftestpath2mod: Dict[Path, types.ModuleType] = {} self._confcutdir: Optional[Path] = None self._noconftest = False + + # _getconftestmodules()'s call to _get_directory() causes a stat + # storm when it's called potentially thousands of times in a test + # session (#9478), often with the same path, so cache it. + self._get_directory = lru_cache(256)(_get_directory) + self._duplicatepaths: Set[Path] = set() # plugins that were explicitly skipped with pytest.skip @@ -530,10 +544,7 @@ class PytestPluginManager(PluginManager): if self._noconftest: return [] - if path.is_file(): - directory = path.parent - else: - directory = path + directory = self._get_directory(path) # Optimization: avoid repeated searches in the same directory. # Assumes always called with same importmode and rootpath.