_getconftestmodules: use functools.lru_cache

Also renames `_path2confmods` to `_dirpath2confmods` for clarity (it is
expected to be a dirpath in `_importconftest`).

Uses an explicit maxsize, since it appears to be only relevant for a
short period [1].

Removes the lru_cache on _getconftest_pathlist, which makes no
difference when caching _getconftestmodules, at least with the
performance test of 100x10 files (#4237).

1: https://github.com/pytest-dev/pytest/pull/4237#discussion_r228528007
This commit is contained in:
Daniel Hahler 2018-10-24 18:50:59 +02:00
parent 233c2a23de
commit ce1cc3dddb
2 changed files with 32 additions and 29 deletions

View File

@ -214,7 +214,7 @@ class PytestPluginManager(PluginManager):
self._conftest_plugins = set() self._conftest_plugins = set()
# state related to local conftest plugins # state related to local conftest plugins
self._path2confmods = {} self._dirpath2confmods = {}
self._conftestpath2mod = {} self._conftestpath2mod = {}
self._confcutdir = None self._confcutdir = None
self._noconftest = False self._noconftest = False
@ -385,31 +385,35 @@ class PytestPluginManager(PluginManager):
if x.check(dir=1): if x.check(dir=1):
self._getconftestmodules(x) self._getconftestmodules(x)
@lru_cache(maxsize=128)
def _getconftestmodules(self, path): def _getconftestmodules(self, path):
if self._noconftest: if self._noconftest:
return [] return []
try: if path.isfile():
return self._path2confmods[path] directory = path.dirpath()
except KeyError: else:
if path.isfile(): directory = path
directory = path.dirpath()
else:
directory = path
# XXX these days we may rather want to use config.rootdir
# and allow users to opt into looking into the rootdir parent
# directories instead of requiring to specify confcutdir
clist = []
for parent in directory.realpath().parts():
if self._confcutdir and self._confcutdir.relto(parent):
continue
conftestpath = parent.join("conftest.py")
if conftestpath.isfile():
mod = self._importconftest(conftestpath)
clist.append(mod)
self._path2confmods[path] = clist if six.PY2: # py2 is not using lru_cache.
return clist try:
return self._dirpath2confmods[directory]
except KeyError:
pass
# XXX these days we may rather want to use config.rootdir
# and allow users to opt into looking into the rootdir parent
# directories instead of requiring to specify confcutdir
clist = []
for parent in directory.realpath().parts():
if self._confcutdir and self._confcutdir.relto(parent):
continue
conftestpath = parent.join("conftest.py")
if conftestpath.isfile():
mod = self._importconftest(conftestpath)
clist.append(mod)
self._dirpath2confmods[directory] = clist
return clist
def _rget_with_confmod(self, name, path): def _rget_with_confmod(self, name, path):
modules = self._getconftestmodules(path) modules = self._getconftestmodules(path)
@ -450,8 +454,8 @@ class PytestPluginManager(PluginManager):
self._conftest_plugins.add(mod) self._conftest_plugins.add(mod)
self._conftestpath2mod[conftestpath] = mod self._conftestpath2mod[conftestpath] = mod
dirpath = conftestpath.dirpath() dirpath = conftestpath.dirpath()
if dirpath in self._path2confmods: if dirpath in self._dirpath2confmods:
for path, mods in self._path2confmods.items(): for path, mods in self._dirpath2confmods.items():
if path and path.relto(dirpath) or path == dirpath: if path and path.relto(dirpath) or path == dirpath:
assert mod not in mods assert mod not in mods
mods.append(mod) mods.append(mod)
@ -902,7 +906,6 @@ class Config(object):
assert type is None assert type is None
return value return value
@lru_cache(maxsize=None)
def _getconftest_pathlist(self, name, path): def _getconftest_pathlist(self, name, path):
try: try:
mod, relroots = self.pluginmanager._rget_with_confmod(name, path) mod, relroots = self.pluginmanager._rget_with_confmod(name, path)

View File

@ -49,14 +49,14 @@ class TestConftestValueAccessGlobal(object):
def test_immediate_initialiation_and_incremental_are_the_same(self, basedir): def test_immediate_initialiation_and_incremental_are_the_same(self, basedir):
conftest = PytestPluginManager() conftest = PytestPluginManager()
len(conftest._path2confmods) len(conftest._dirpath2confmods)
conftest._getconftestmodules(basedir) conftest._getconftestmodules(basedir)
snap1 = len(conftest._path2confmods) snap1 = len(conftest._dirpath2confmods)
# assert len(conftest._path2confmods) == snap1 + 1 # assert len(conftest._dirpath2confmods) == snap1 + 1
conftest._getconftestmodules(basedir.join("adir")) conftest._getconftestmodules(basedir.join("adir"))
assert len(conftest._path2confmods) == snap1 + 1 assert len(conftest._dirpath2confmods) == snap1 + 1
conftest._getconftestmodules(basedir.join("b")) conftest._getconftestmodules(basedir.join("b"))
assert len(conftest._path2confmods) == snap1 + 2 assert len(conftest._dirpath2confmods) == snap1 + 2
def test_value_access_not_existing(self, basedir): def test_value_access_not_existing(self, basedir):
conftest = ConftestWithSetinitial(basedir) conftest = ConftestWithSetinitial(basedir)