Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions changelog/14454.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a regression where :option:`-c` pointing to a config file in a sub-directory would set :confval:`rootdir` to the config file's parent directory instead of the invocation directory, breaking conftest discovery. Patch by :user:`EternalRights`.
12 changes: 12 additions & 0 deletions src/_pytest/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import importlib
import importlib.metadata
import inspect
import logging
import os
import pathlib
import re
Expand Down Expand Up @@ -78,6 +79,9 @@
from _pytest.warning_types import warn_explicit_for


log = logging.getLogger(__name__)


if TYPE_CHECKING:
from _pytest.assertion.rewrite import AssertionRewritingHook
from _pytest.cacheprovider import Cache
Expand Down Expand Up @@ -1501,6 +1505,14 @@ def parse(self, args: list[str], addopts: bool = True) -> None:
self._parser.extra_info["rootdir"] = str(self.rootpath)
self._parser.extra_info["inifile"] = str(self.inipath)

if ns.inifilename and not ns.rootdir:
if inipath is not None and inipath.parent != self.invocation_params.dir:
log.warning(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pytest doesnt use logging for ux we might want to find a differnt place to output this

@nicoddemus @bluetech any opinion on this - personally i lean towards the pre collection summary header that shows pytest/plugin versions + config paths already but something about that feels icky as well

"rootdir was set to %s because -c was given without --rootdir. "
"Use --rootdir to explicitly disambiguate.",
self.invocation_params.dir,
)

self._parser.addini("addopts", "Extra command line options", "args")
self._parser.addini("minversion", "Minimally required pytest version")
self._parser.addini(
Expand Down
2 changes: 1 addition & 1 deletion src/_pytest/config/findpaths.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def determine_setup(
inipath: Path | None = inipath_
inicfg = load_config_dict_from_file(inipath_) or {}
if rootdir_cmd_arg is None:
rootdir = inipath_.parent
rootdir = invocation_dir
else:
ancestor = get_common_ancestor(invocation_dir, dirs)
rootdir, inipath, inicfg, ignored_config_files = locate_config(
Expand Down
63 changes: 62 additions & 1 deletion testing/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2028,12 +2028,73 @@ def test_with_specific_inifile(
override_ini=None,
args=[str(tmp_path)],
rootdir_cmd_arg=None,
invocation_dir=Path.cwd(),
invocation_dir=tmp_path,
)
assert rootpath == tmp_path
assert inipath == p
assert ini_config["x"] == ConfigValue("10", origin="file", mode="ini")

def test_config_in_subdir_does_not_change_rootdir(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Config file in a subdir should not move rootdir to that subdir (#13246)."""
config_dir = tmp_path / "config"
config_dir.mkdir()
inipath = config_dir / "pytest.ini"
inipath.touch()
monkeypatch.chdir(tmp_path)

rootpath, found_inipath, *_ = determine_setup(
inifile=str(inipath),
override_ini=None,
args=[],
rootdir_cmd_arg=None,
invocation_dir=Path.cwd(),
)
assert rootpath == tmp_path, (
f"rootdir should be invocation_dir ({tmp_path}), got {rootpath}"
)
assert found_inipath == inipath

def test_rootdir_warning_when_config_in_subdir(
self, tmp_path: Path, caplog: pytest.LogCaptureFixture
) -> None:
"""When -c points to a subdir, a warning should be logged (#13246)."""
import logging

config_dir = tmp_path / "config"
config_dir.mkdir()
inipath = config_dir / "pytest.ini"
inipath.touch()

caplog.set_level(logging.WARNING)
Config.fromdictargs(
{"inifilename": str(inipath)}, # -c config/pytest.ini
[],
)

assert len(caplog.records) >= 1
assert "rootdir was set to" in caplog.records[0].message
assert "--rootdir" in caplog.records[0].message

def test_no_warning_when_config_in_rootdir(
self, tmp_path: Path, monkeypatch: MonkeyPatch, caplog: pytest.LogCaptureFixture
) -> None:
"""When -c points to the invocation dir itself, no warning needed (#13246)."""
import logging

inipath = tmp_path / "pytest.ini"
inipath.touch()
monkeypatch.chdir(tmp_path)

caplog.set_level(logging.WARNING)
Config.fromdictargs(
{"inifilename": str(inipath)},
[],
)

assert len(caplog.records) == 0

def test_explicit_config_file_sets_rootdir(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
Expand Down
Loading