Skip to content

config: split _getconftestmodules and _loadconftestmodules #11268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 14 additions & 18 deletions src/_pytest/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,26 +581,25 @@ def _is_in_confcutdir(self, path: Path) -> bool:
def _try_load_conftest(
self, anchor: Path, importmode: Union[str, ImportMode], rootpath: Path
) -> None:
self._getconftestmodules(anchor, importmode, rootpath)
self._loadconftestmodules(anchor, importmode, rootpath)
# let's also consider test* subdirs
if anchor.is_dir():
for x in anchor.glob("test*"):
if x.is_dir():
self._getconftestmodules(x, importmode, rootpath)
self._loadconftestmodules(x, importmode, rootpath)

def _getconftestmodules(
def _loadconftestmodules(
self, path: Path, importmode: Union[str, ImportMode], rootpath: Path
) -> Sequence[types.ModuleType]:
) -> None:
if self._noconftest:
return []
return

directory = self._get_directory(path)

# Optimization: avoid repeated searches in the same directory.
# Assumes always called with same importmode and rootpath.
existing_clist = self._dirpath2confmods.get(directory)
if existing_clist is not None:
return existing_clist
if directory in self._dirpath2confmods:
return

# XXX these days we may rather want to use config.rootpath
# and allow users to opt into looking into the rootdir parent
Expand All @@ -613,16 +612,17 @@ def _getconftestmodules(
mod = self._importconftest(conftestpath, importmode, rootpath)
clist.append(mod)
self._dirpath2confmods[directory] = clist
return clist

def _getconftestmodules(self, path: Path) -> Sequence[types.ModuleType]:
directory = self._get_directory(path)
return self._dirpath2confmods.get(directory, ())

def _rget_with_confmod(
self,
name: str,
path: Path,
importmode: Union[str, ImportMode],
rootpath: Path,
) -> Tuple[types.ModuleType, Any]:
modules = self._getconftestmodules(path, importmode, rootpath=rootpath)
modules = self._getconftestmodules(path)
for mod in reversed(modules):
try:
return mod, getattr(mod, name)
Expand Down Expand Up @@ -1562,13 +1562,9 @@ def _getini(self, name: str):
else:
return self._getini_unknown_type(name, type, value)

def _getconftest_pathlist(
self, name: str, path: Path, rootpath: Path
) -> Optional[List[Path]]:
def _getconftest_pathlist(self, name: str, path: Path) -> Optional[List[Path]]:
try:
mod, relroots = self.pluginmanager._rget_with_confmod(
name, path, self.getoption("importmode"), rootpath
)
mod, relroots = self.pluginmanager._rget_with_confmod(name, path)
except KeyError:
return None
assert mod.__file__ is not None
Expand Down
11 changes: 8 additions & 3 deletions src/_pytest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ def _in_venv(path: Path) -> bool:

def pytest_ignore_collect(collection_path: Path, config: Config) -> Optional[bool]:
ignore_paths = config._getconftest_pathlist(
"collect_ignore", path=collection_path.parent, rootpath=config.rootpath
"collect_ignore", path=collection_path.parent
)
ignore_paths = ignore_paths or []
excludeopt = config.getoption("ignore")
Expand All @@ -387,7 +387,7 @@ def pytest_ignore_collect(collection_path: Path, config: Config) -> Optional[boo
return True

ignore_globs = config._getconftest_pathlist(
"collect_ignore_glob", path=collection_path.parent, rootpath=config.rootpath
"collect_ignore_glob", path=collection_path.parent
)
ignore_globs = ignore_globs or []
excludeglobopt = config.getoption("ignore_glob")
Expand Down Expand Up @@ -551,11 +551,16 @@ def gethookproxy(self, fspath: "os.PathLike[str]"):
pm = self.config.pluginmanager
# Check if we have the common case of running
# hooks with all conftest.py files.
my_conftestmodules = pm._getconftestmodules(
#
# TODO: pytest relies on this call to load non-initial conftests. This
# is incidental. It will be better to load conftests at a more
# well-defined place.
pm._loadconftestmodules(
path,
self.config.getoption("importmode"),
rootpath=self.config.rootpath,
)
my_conftestmodules = pm._getconftestmodules(path)
remove_mods = pm._conftest_plugins.difference(my_conftestmodules)
if remove_mods:
# One or more conftests are not in use at this fspath.
Expand Down
4 changes: 1 addition & 3 deletions testing/python/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -2103,9 +2103,7 @@ def test_2(self):
reprec = pytester.inline_run("-v", "-s", "--confcutdir", pytester.path)
reprec.assertoutcome(passed=8)
config = reprec.getcalls("pytest_unconfigure")[0].config
values = config.pluginmanager._getconftestmodules(
p, importmode="prepend", rootpath=pytester.path
)[0].values
values = config.pluginmanager._getconftestmodules(p)[0].values
assert values == ["fin_a1", "fin_a2", "fin_b1", "fin_b2"] * 2

def test_scope_ordering(self, pytester: Pytester) -> None:
Expand Down
17 changes: 5 additions & 12 deletions testing/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,18 +642,11 @@ def test_getconftest_pathlist(self, pytester: Pytester, tmp_path: Path) -> None:
p = tmp_path.joinpath("conftest.py")
p.write_text(f"mylist = {['.', str(somepath)]}", encoding="utf-8")
config = pytester.parseconfigure(p)
assert (
config._getconftest_pathlist("notexist", path=tmp_path, rootpath=tmp_path)
is None
)
pl = (
config._getconftest_pathlist("mylist", path=tmp_path, rootpath=tmp_path)
or []
)
print(pl)
assert len(pl) == 2
assert pl[0] == tmp_path
assert pl[1] == somepath
assert config._getconftest_pathlist("notexist", path=tmp_path) is None
assert config._getconftest_pathlist("mylist", path=tmp_path) == [
tmp_path,
somepath,
]

@pytest.mark.parametrize("maybe_type", ["not passed", "None", '"string"'])
def test_addini(self, pytester: Pytester, maybe_type: str) -> None:
Expand Down
70 changes: 22 additions & 48 deletions testing/test_conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,62 +62,46 @@ def basedir(
def test_basic_init(self, basedir: Path) -> None:
conftest = PytestPluginManager()
p = basedir / "adir"
assert (
conftest._rget_with_confmod("a", p, importmode="prepend", rootpath=basedir)[
1
]
== 1
)
conftest._loadconftestmodules(p, importmode="prepend", rootpath=basedir)
assert conftest._rget_with_confmod("a", p)[1] == 1

def test_immediate_initialiation_and_incremental_are_the_same(
self, basedir: Path
) -> None:
conftest = PytestPluginManager()
assert not len(conftest._dirpath2confmods)
conftest._getconftestmodules(
basedir, importmode="prepend", rootpath=Path(basedir)
)
conftest._loadconftestmodules(basedir, importmode="prepend", rootpath=basedir)
snap1 = len(conftest._dirpath2confmods)
assert snap1 == 1
conftest._getconftestmodules(
conftest._loadconftestmodules(
basedir / "adir", importmode="prepend", rootpath=basedir
)
assert len(conftest._dirpath2confmods) == snap1 + 1
conftest._getconftestmodules(
conftest._loadconftestmodules(
basedir / "b", importmode="prepend", rootpath=basedir
)
assert len(conftest._dirpath2confmods) == snap1 + 2

def test_value_access_not_existing(self, basedir: Path) -> None:
conftest = ConftestWithSetinitial(basedir)
with pytest.raises(KeyError):
conftest._rget_with_confmod(
"a", basedir, importmode="prepend", rootpath=Path(basedir)
)
conftest._rget_with_confmod("a", basedir)

def test_value_access_by_path(self, basedir: Path) -> None:
conftest = ConftestWithSetinitial(basedir)
adir = basedir / "adir"
assert (
conftest._rget_with_confmod(
"a", adir, importmode="prepend", rootpath=basedir
)[1]
== 1
)
assert (
conftest._rget_with_confmod(
"a", adir / "b", importmode="prepend", rootpath=basedir
)[1]
== 1.5
conftest._loadconftestmodules(adir, importmode="prepend", rootpath=basedir)
assert conftest._rget_with_confmod("a", adir)[1] == 1
conftest._loadconftestmodules(
adir / "b", importmode="prepend", rootpath=basedir
)
assert conftest._rget_with_confmod("a", adir / "b")[1] == 1.5

def test_value_access_with_confmod(self, basedir: Path) -> None:
startdir = basedir / "adir" / "b"
startdir.joinpath("xx").mkdir()
conftest = ConftestWithSetinitial(startdir)
mod, value = conftest._rget_with_confmod(
"a", startdir, importmode="prepend", rootpath=Path(basedir)
)
mod, value = conftest._rget_with_confmod("a", startdir)
assert value == 1.5
assert mod.__file__ is not None
path = Path(mod.__file__)
Expand All @@ -143,9 +127,7 @@ def test_doubledash_considered(pytester: Pytester) -> None:
conf.joinpath("conftest.py").touch()
conftest = PytestPluginManager()
conftest_setinitial(conftest, [conf.name, conf.name])
values = conftest._getconftestmodules(
conf, importmode="prepend", rootpath=pytester.path
)
values = conftest._getconftestmodules(conf)
assert len(values) == 1


Expand Down Expand Up @@ -192,26 +174,22 @@ def test_conftestcutdir(pytester: Pytester) -> None:
p = pytester.mkdir("x")
conftest = PytestPluginManager()
conftest_setinitial(conftest, [pytester.path], confcutdir=p)
values = conftest._getconftestmodules(
p, importmode="prepend", rootpath=pytester.path
)
conftest._loadconftestmodules(p, importmode="prepend", rootpath=pytester.path)
values = conftest._getconftestmodules(p)
assert len(values) == 0
values = conftest._getconftestmodules(
conftest._loadconftestmodules(
conf.parent, importmode="prepend", rootpath=pytester.path
)
values = conftest._getconftestmodules(conf.parent)
assert len(values) == 0
assert not conftest.has_plugin(str(conf))
# but we can still import a conftest directly
conftest._importconftest(conf, importmode="prepend", rootpath=pytester.path)
values = conftest._getconftestmodules(
conf.parent, importmode="prepend", rootpath=pytester.path
)
values = conftest._getconftestmodules(conf.parent)
assert values[0].__file__ is not None
assert values[0].__file__.startswith(str(conf))
# and all sub paths get updated properly
values = conftest._getconftestmodules(
p, importmode="prepend", rootpath=pytester.path
)
values = conftest._getconftestmodules(p)
assert len(values) == 1
assert values[0].__file__ is not None
assert values[0].__file__.startswith(str(conf))
Expand All @@ -221,9 +199,7 @@ def test_conftestcutdir_inplace_considered(pytester: Pytester) -> None:
conf = pytester.makeconftest("")
conftest = PytestPluginManager()
conftest_setinitial(conftest, [conf.parent], confcutdir=conf.parent)
values = conftest._getconftestmodules(
conf.parent, importmode="prepend", rootpath=pytester.path
)
values = conftest._getconftestmodules(conf.parent)
assert len(values) == 1
assert values[0].__file__ is not None
assert values[0].__file__.startswith(str(conf))
Expand Down Expand Up @@ -433,10 +409,8 @@ def impct(p, importmode, root):
conftest = PytestPluginManager()
conftest._confcutdir = pytester.path
monkeypatch.setattr(conftest, "_importconftest", impct)
mods = cast(
List[Path],
conftest._getconftestmodules(sub, importmode="prepend", rootpath=pytester.path),
)
conftest._loadconftestmodules(sub, importmode="prepend", rootpath=pytester.path)
mods = cast(List[Path], conftest._getconftestmodules(sub))
expected = [ct1, ct2]
assert mods == expected

Expand Down