Skip to content

Commit 6639d6c

Browse files
committed
Merge pull request pytest-dev#9532 from bluetech/getdir-cache
config: avoid stat storm in _getconftestmodules (cherry picked from commit 5c69ece) Conflicts: src/_pytest/config/__init__.py
1 parent 5c49dea commit 6639d6c

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

src/_pytest/config/__init__.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,14 @@ def _prepareconfig(
331331
raise
332332

333333

334+
def _get_directory(path: Path) -> Path:
335+
"""Get the directory of a path - itself if already a directory."""
336+
if path.is_file():
337+
return path.parent
338+
else:
339+
return path
340+
341+
334342
@final
335343
class PytestPluginManager(PluginManager):
336344
"""A :py:class:`pluggy.PluginManager <pluggy.PluginManager>` with
@@ -353,6 +361,12 @@ def __init__(self) -> None:
353361
self._conftestpath2mod: Dict[Path, types.ModuleType] = {}
354362
self._confcutdir: Optional[Path] = None
355363
self._noconftest = False
364+
365+
# _getconftestmodules()'s call to _get_directory() causes a stat
366+
# storm when it's called potentially thousands of times in a test
367+
# session (#9478), often with the same path, so cache it.
368+
self._get_directory = lru_cache(256)(_get_directory)
369+
356370
self._duplicatepaths: Set[Path] = set()
357371

358372
# plugins that were explicitly skipped with pytest.skip
@@ -530,10 +544,7 @@ def _getconftestmodules(
530544
if self._noconftest:
531545
return []
532546

533-
if path.is_file():
534-
directory = path.parent
535-
else:
536-
directory = path
547+
directory = self._get_directory(path)
537548

538549
# Optimization: avoid repeated searches in the same directory.
539550
# Assumes always called with same importmode and rootpath.

0 commit comments

Comments
 (0)