Skip to content

Commit

Permalink
Consider pyproject.toml files for config if no other config files wer…
Browse files Browse the repository at this point in the history
…e found

Today `pyproject.toml` is the standard for declaring a Python project root, so seems reasonable to consider it for the ini configuration (and specially `rootdir`) in case we do not find other suitable candidates.

Related to #11311
  • Loading branch information
nicoddemus committed Feb 10, 2024
1 parent 7690a0d commit b599919
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 1 deletion.
1 change: 1 addition & 0 deletions changelog/11962.improvement.rst
@@ -0,0 +1 @@
In case no other suitable candidates for configuration file are found, a ``pyproject.toml`` (even without a ``[tool.pytest.ini_options]`` table) will be considered as the configuration file and define the ``rootdir``.
3 changes: 3 additions & 0 deletions doc/en/reference/customize.rst
Expand Up @@ -177,6 +177,9 @@ Files will only be matched for configuration if:
* ``tox.ini``: contains a ``[pytest]`` section.
* ``setup.cfg``: contains a ``[tool:pytest]`` section.

Finally, a ``pyproject.toml`` file will be considered the ``configfile`` if no other match was found, in this case
even if it does not contain a ``[tool.pytest.ini_options]`` table (this was added in ``8.1``).

The files are considered in the order above. Options from multiple ``configfiles`` candidates
are never merged - the first match wins.

Expand Down
5 changes: 5 additions & 0 deletions src/_pytest/config/findpaths.py
Expand Up @@ -101,15 +101,20 @@ def locate_config(
args = [x for x in args if not str(x).startswith("-")]
if not args:
args = [invocation_dir]
found_pyproject_toml: Optional[Path] = None
for arg in args:
argpath = absolutepath(arg)
for base in (argpath, *argpath.parents):
for config_name in config_names:
p = base / config_name
if p.is_file():
if p.name == "pyproject.toml" and found_pyproject_toml is None:
found_pyproject_toml = p
ini_config = load_config_dict_from_file(p)
if ini_config is not None:
return base, p, ini_config
if found_pyproject_toml is not None:
return found_pyproject_toml.parent, found_pyproject_toml, {}

Check warning on line 117 in src/_pytest/config/findpaths.py

View check run for this annotation

Codecov / codecov/patch

src/_pytest/config/findpaths.py#L117

Added line #L117 was not covered by tests
return None, None, {}


Expand Down
32 changes: 31 additions & 1 deletion testing/test_config.py
Expand Up @@ -135,15 +135,45 @@ def test_ini_names(self, pytester: Pytester, name, section) -> None:
assert config.getini("minversion") == "3.36"

def test_pyproject_toml(self, pytester: Pytester) -> None:
pytester.makepyprojecttoml(
pyproject_toml = pytester.makepyprojecttoml(
"""
[tool.pytest.ini_options]
minversion = "1.0"
"""
)
config = pytester.parseconfig()
assert config.inipath == pyproject_toml
assert config.getini("minversion") == "1.0"

def test_empty_pyproject_toml(self, pytester: Pytester) -> None:
"""An empty pyproject.toml is considered as config if no other option is found."""
pyproject_toml = pytester.makepyprojecttoml("")
config = pytester.parseconfig()
assert config.inipath == pyproject_toml

def test_empty_pyproject_toml_found_many(self, pytester: Pytester) -> None:
"""
In case we find multiple pyproject.toml files in our search, without a [tool.pytest.ini_options]
table and without finding other candidates, the closest to where we started wins.
"""
pytester.makefile(
".toml",
**{
"pyproject": "",
"foo/pyproject": "",
"foo/bar/pyproject": "",
},
)
config = pytester.parseconfig(pytester.path / "foo/bar")
assert config.inipath == pytester.path / "foo/bar/pyproject.toml"

def test_pytest_ini_trumps_pyproject_toml(self, pytester: Pytester) -> None:
"""An empty pyproject.toml is considered as config if no other option is found."""
pytester.makepyprojecttoml("[tool.pytest.ini_options]")
pytest_ini = pytester.makefile(".ini", pytest="")
config = pytester.parseconfig()
assert config.inipath == pytest_ini

def test_toxini_before_lower_pytestini(self, pytester: Pytester) -> None:
sub = pytester.mkdir("sub")
sub.joinpath("tox.ini").write_text(
Expand Down

0 comments on commit b599919

Please sign in to comment.