Skip to content
Closed
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
6 changes: 5 additions & 1 deletion src/_pytest/config/findpaths.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,12 @@ def load_config_dict_from_file(
raise UsageError(f"{filepath}: {exc}") from exc

# pytest.toml and .pytest.toml use [pytest] table directly.
# Top-level non-table keys are also treated as pytest config,
# since the filename already identifies the context and TOML
# sections are optional.
if filepath.name in ("pytest.toml", ".pytest.toml"):
pytest_config = config.get("pytest", {})
top_config = {k: v for k, v in config.items() if not isinstance(v, dict)}
pytest_config = {**top_config, **config.get("pytest", {})}
if pytest_config:
# TOML mode - preserve native TOML types.
return {
Expand Down
14 changes: 14 additions & 0 deletions testing/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,20 @@ def test_empty_pytest_toml(self, pytester: Pytester, name: str) -> None:
config = pytester.parseconfig()
assert config.inipath == pytest_toml

@pytest.mark.parametrize("name", ["pytest.toml", ".pytest.toml"])
def test_headerless_pytest_toml(self, pytester: Pytester, name: str) -> None:
"""Top-level keys in pytest.toml are treated as pytest config (#14638)."""
pytester.path.joinpath(name).write_text(
textwrap.dedent(
"""
minversion = "9.0"
"""
),
encoding="utf-8",
)
config = pytester.parseconfig()
assert config.getini("minversion") == "9.0"

def test_pytest_toml_trumps_pyproject_toml(self, pytester: Pytester) -> None:
"""A pytest.toml always takes precedence over a pyproject.toml file."""
pytester.makepyprojecttoml(
Expand Down
Loading