Skip to content

Commit ab44bec

Browse files
committed
config: make ConfigValue.origin kw-only
I am going to add another field, then it will start being ambiguous, so make it kw-only to ensure clarity.
1 parent 543d9aa commit ab44bec

File tree

3 files changed

+30
-19
lines changed

3 files changed

+30
-19
lines changed

src/_pytest/config/findpaths.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from collections.abc import Iterable
44
from collections.abc import Sequence
55
from dataclasses import dataclass
6+
from dataclasses import KW_ONLY
67
import os
78
from pathlib import Path
89
import sys
@@ -31,6 +32,7 @@ class ConfigValue:
3132
# str/list[str] during parsing to maintain compatibility with the rest of
3233
# the configuration system.
3334
value: str | list[str]
35+
_: KW_ONLY
3436
origin: Literal["file", "override"]
3537

3638

@@ -61,7 +63,9 @@ def load_config_dict_from_file(
6163
iniconfig = _parse_ini_config(filepath)
6264

6365
if "pytest" in iniconfig:
64-
return {k: ConfigValue(v, "file") for k, v in iniconfig["pytest"].items()}
66+
return {
67+
k: ConfigValue(v, origin="file") for k, v in iniconfig["pytest"].items()
68+
}
6569
else:
6670
# "pytest.ini" files are always the source of configuration, even if empty.
6771
if filepath.name == "pytest.ini":
@@ -73,7 +77,8 @@ def load_config_dict_from_file(
7377

7478
if "tool:pytest" in iniconfig.sections:
7579
return {
76-
k: ConfigValue(v, "file") for k, v in iniconfig["tool:pytest"].items()
80+
k: ConfigValue(v, origin="file")
81+
for k, v in iniconfig["tool:pytest"].items()
7782
}
7883
elif "pytest" in iniconfig.sections:
7984
# If a setup.cfg contains a "[pytest]" section, we raise a failure to indicate users that
@@ -101,7 +106,9 @@ def load_config_dict_from_file(
101106
def make_scalar(v: object) -> str | list[str]:
102107
return v if isinstance(v, list) else str(v)
103108

104-
return {k: ConfigValue(make_scalar(v), "file") for k, v in result.items()}
109+
return {
110+
k: ConfigValue(make_scalar(v), origin="file") for k, v in result.items()
111+
}
105112

106113
return None
107114

@@ -217,7 +224,7 @@ def parse_override_ini(override_ini: Sequence[str] | None) -> ConfigDict:
217224
f"-o/--override-ini expects option=value style (got: {ini_config!r})."
218225
) from e
219226
else:
220-
overrides[key] = ConfigValue(user_ini_value, "override")
227+
overrides[key] = ConfigValue(user_ini_value, origin="override")
221228
return overrides
222229

223230

testing/test_config.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ def test_getcfg_and_config(
5858
encoding="utf-8",
5959
)
6060
_, _, cfg, _ = locate_config(Path.cwd(), [sub])
61-
assert cfg["name"] == ConfigValue("value", "file")
61+
assert cfg["name"] == ConfigValue("value", origin="file")
6262
config = pytester.parseconfigure(str(sub))
63-
assert config.inicfg["name"] == ConfigValue("value", "file")
63+
assert config.inicfg["name"] == ConfigValue("value", origin="file")
6464

6565
def test_setupcfg_uses_toolpytest_with_pytest(self, pytester: Pytester) -> None:
6666
p1 = pytester.makepyfile("def test(): pass")
@@ -1314,7 +1314,7 @@ def test_inifilename(self, tmp_path: Path) -> None:
13141314

13151315
# this indicates this is the file used for getting configuration values
13161316
assert config.inipath == inipath
1317-
assert config.inicfg.get("name") == ConfigValue("value", "file")
1317+
assert config.inicfg.get("name") == ConfigValue("value", origin="file")
13181318
assert config.inicfg.get("should_not_be_set") is None
13191319

13201320

@@ -1808,7 +1808,7 @@ def test_with_ini(self, tmp_path: Path, name: str, contents: str) -> None:
18081808
)
18091809
assert rootpath == tmp_path
18101810
assert parsed_inipath == inipath
1811-
assert ini_config["x"] == ConfigValue("10", "file")
1811+
assert ini_config["x"] == ConfigValue("10", origin="file")
18121812

18131813
@pytest.mark.parametrize("name", ["setup.cfg", "tox.ini"])
18141814
def test_pytestini_overrides_empty_other(self, tmp_path: Path, name: str) -> None:
@@ -1882,7 +1882,7 @@ def test_with_specific_inifile(
18821882
)
18831883
assert rootpath == tmp_path
18841884
assert inipath == p
1885-
assert ini_config["x"] == ConfigValue("10", "file")
1885+
assert ini_config["x"] == ConfigValue("10", origin="file")
18861886

18871887
def test_explicit_config_file_sets_rootdir(
18881888
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
@@ -2152,7 +2152,9 @@ def test_addopts_before_initini(
21522152
monkeypatch.setenv("PYTEST_ADDOPTS", f"-o cache_dir={cache_dir}")
21532153
config = _config_for_test
21542154
config._preparse([], addopts=True)
2155-
assert config.inicfg.get("cache_dir") == ConfigValue(cache_dir, "override")
2155+
assert config.inicfg.get("cache_dir") == ConfigValue(
2156+
cache_dir, origin="override"
2157+
)
21562158

21572159
def test_addopts_from_env_not_concatenated(
21582160
self, monkeypatch: MonkeyPatch, _config_for_test
@@ -2190,7 +2192,9 @@ def test_override_ini_does_not_contain_paths(
21902192
"""Check that -o no longer swallows all options after it (#3103)"""
21912193
config = _config_for_test
21922194
config._preparse(["-o", "cache_dir=/cache", "/some/test/path"])
2193-
assert config.inicfg.get("cache_dir") == ConfigValue("/cache", "override")
2195+
assert config.inicfg.get("cache_dir") == ConfigValue(
2196+
"/cache", origin="override"
2197+
)
21942198

21952199
def test_multiple_override_ini_options(self, pytester: Pytester) -> None:
21962200
"""Ensure a file path following a '-o' option does not generate an error (#3103)"""

testing/test_findpaths.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ def test_pytest_ini(self, tmp_path: Path) -> None:
2525
"""[pytest] section in pytest.ini files is read correctly"""
2626
fn = tmp_path / "pytest.ini"
2727
fn.write_text("[pytest]\nx=1", encoding="utf-8")
28-
assert load_config_dict_from_file(fn) == {"x": ConfigValue("1", "file")}
28+
assert load_config_dict_from_file(fn) == {"x": ConfigValue("1", origin="file")}
2929

3030
def test_custom_ini(self, tmp_path: Path) -> None:
3131
"""[pytest] section in any .ini file is read correctly"""
3232
fn = tmp_path / "custom.ini"
3333
fn.write_text("[pytest]\nx=1", encoding="utf-8")
34-
assert load_config_dict_from_file(fn) == {"x": ConfigValue("1", "file")}
34+
assert load_config_dict_from_file(fn) == {"x": ConfigValue("1", origin="file")}
3535

3636
def test_custom_ini_without_section(self, tmp_path: Path) -> None:
3737
"""Custom .ini files without [pytest] section are not considered for configuration"""
@@ -49,7 +49,7 @@ def test_valid_cfg_file(self, tmp_path: Path) -> None:
4949
"""Custom .cfg files with [tool:pytest] section are read correctly"""
5050
fn = tmp_path / "custom.cfg"
5151
fn.write_text("[tool:pytest]\nx=1", encoding="utf-8")
52-
assert load_config_dict_from_file(fn) == {"x": ConfigValue("1", "file")}
52+
assert load_config_dict_from_file(fn) == {"x": ConfigValue("1", origin="file")}
5353

5454
def test_unsupported_pytest_section_in_cfg_file(self, tmp_path: Path) -> None:
5555
""".cfg files with [pytest] section are no longer supported and should fail to alert users"""
@@ -97,11 +97,11 @@ def test_valid_toml_file(self, tmp_path: Path) -> None:
9797
encoding="utf-8",
9898
)
9999
assert load_config_dict_from_file(fn) == {
100-
"x": ConfigValue("1", "file"),
101-
"y": ConfigValue("20.0", "file"),
102-
"values": ConfigValue(["tests", "integration"], "file"),
103-
"name": ConfigValue("foo", "file"),
104-
"heterogeneous_array": ConfigValue([1, "str"], "file"), # type: ignore[list-item]
100+
"x": ConfigValue("1", origin="file"),
101+
"y": ConfigValue("20.0", origin="file"),
102+
"values": ConfigValue(["tests", "integration"], origin="file"),
103+
"name": ConfigValue("foo", origin="file"),
104+
"heterogeneous_array": ConfigValue([1, "str"], origin="file"), # type: ignore[list-item]
105105
}
106106

107107

0 commit comments

Comments
 (0)