Skip to content

Commit e77ce02

Browse files
committed
Refactor getcfg function for clarity
This makes it clear each type of file that it is supported. Also dropped 'config' parameter as it is no longer used.
1 parent 69d2ddc commit e77ce02

File tree

3 files changed

+77
-39
lines changed

3 files changed

+77
-39
lines changed

src/_pytest/config/__init__.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,13 +1064,8 @@ def _checkversion(self):
10641064

10651065
if Version(minver) > Version(pytest.__version__):
10661066
raise pytest.UsageError(
1067-
"%s:%d: requires pytest-%s, actual pytest-%s'"
1068-
% (
1069-
self.inicfg.config.path,
1070-
self.inicfg.lineof("minversion"),
1071-
minver,
1072-
pytest.__version__,
1073-
)
1067+
"%s: 'minversion' requires pytest-%s, actual pytest-%s'"
1068+
% (self.inifile, minver, pytest.__version__,)
10741069
)
10751070

10761071
def _validatekeys(self):
@@ -1144,7 +1139,7 @@ def _getini(self, name: str) -> Any:
11441139
return ""
11451140
return []
11461141
if type == "pathlist":
1147-
dp = py.path.local(self.inicfg.config.path).dirpath()
1142+
dp = py.path.local(self.inifile).dirpath()
11481143
values = []
11491144
for relpath in shlex.split(value):
11501145
values.append(dp.join(relpath, abs=True))

src/_pytest/config/findpaths.py

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from typing import Any
3+
from typing import Dict
34
from typing import Iterable
45
from typing import List
56
from typing import Optional
@@ -22,44 +23,84 @@ def exists(path, ignore=OSError):
2223
return False
2324

2425

25-
def getcfg(args, config=None):
26+
def _parse_ini_config(path: py.path.local) -> py.iniconfig.IniConfig:
27+
"""Parses the given generic '.ini' file using legacy IniConfig parser, returning
28+
the parsed object.
29+
30+
Raises UsageError if the file cannot be parsed.
31+
"""
32+
try:
33+
return py.iniconfig.IniConfig(path)
34+
except py.iniconfig.ParseError as exc:
35+
raise UsageError(str(exc))
36+
37+
38+
def _get_ini_config_from_pytest_ini(path: py.path.local) -> Optional[Dict[str, Any]]:
39+
"""Parses and validates a 'pytest.ini' file.
40+
41+
If present, 'pytest.ini' files are always considered the source of truth of pytest
42+
configuration, even if empty or without a "[pytest]" section.
43+
"""
44+
iniconfig = _parse_ini_config(path)
45+
if "pytest" in iniconfig:
46+
return dict(iniconfig["pytest"].items())
47+
else:
48+
return {}
49+
50+
51+
def _get_ini_config_from_tox_ini(path: py.path.local) -> Optional[Dict[str, Any]]:
52+
"""Parses and validates a 'tox.ini' file for pytest configuration.
53+
54+
'tox.ini' files are only considered for pytest configuration if they contain a "[pytest]"
55+
section.
56+
"""
57+
iniconfig = _parse_ini_config(path)
58+
if "pytest" in iniconfig:
59+
return dict(iniconfig["pytest"].items())
60+
else:
61+
return None
62+
63+
64+
def _get_ini_config_from_setup_cfg(path: py.path.local) -> Optional[Dict[str, Any]]:
65+
"""Parses and validates a 'setup.cfg' file for pytest configuration.
66+
67+
'setup.cfg' files are only considered for pytest configuration if they contain a "[tool:pytest]"
68+
section.
69+
70+
If a setup.cfg contains a "[pytest]" section, we raise a failure to indicate users that
71+
plain "[pytest]" sections in setup.cfg files is no longer supported (#3086).
72+
"""
73+
iniconfig = _parse_ini_config(path)
74+
75+
if "tool:pytest" in iniconfig.sections:
76+
return dict(iniconfig["tool:pytest"].items())
77+
elif "pytest" in iniconfig.sections:
78+
fail(CFG_PYTEST_SECTION.format(filename="setup.cfg"), pytrace=False)
79+
return None
80+
81+
82+
def getcfg(args):
2683
"""
2784
Search the list of arguments for a valid ini-file for pytest,
2885
and return a tuple of (rootdir, inifile, cfg-dict).
29-
30-
note: config is optional and used only to issue warnings explicitly (#2891).
3186
"""
32-
inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"]
87+
ini_names_and_handlers = [
88+
("pytest.ini", _get_ini_config_from_pytest_ini),
89+
("tox.ini", _get_ini_config_from_tox_ini),
90+
("setup.cfg", _get_ini_config_from_setup_cfg),
91+
]
3392
args = [x for x in args if not str(x).startswith("-")]
3493
if not args:
3594
args = [py.path.local()]
3695
for arg in args:
3796
arg = py.path.local(arg)
3897
for base in arg.parts(reverse=True):
39-
for inibasename in inibasenames:
98+
for inibasename, handler in ini_names_and_handlers:
4099
p = base.join(inibasename)
41-
if exists(p):
42-
try:
43-
iniconfig = py.iniconfig.IniConfig(p)
44-
except py.iniconfig.ParseError as exc:
45-
raise UsageError(str(exc))
46-
47-
if (
48-
inibasename == "setup.cfg"
49-
and "tool:pytest" in iniconfig.sections
50-
):
51-
return base, p, iniconfig["tool:pytest"]
52-
elif "pytest" in iniconfig.sections:
53-
if inibasename == "setup.cfg" and config is not None:
54-
55-
fail(
56-
CFG_PYTEST_SECTION.format(filename=inibasename),
57-
pytrace=False,
58-
)
59-
return base, p, iniconfig["pytest"]
60-
elif inibasename == "pytest.ini":
61-
# allowed to be empty
62-
return base, p, {}
100+
if p.isfile():
101+
ini_config = handler(p)
102+
if ini_config is not None:
103+
return base, p, ini_config
63104
return None, None, None
64105

65106

@@ -138,15 +179,15 @@ def determine_setup(
138179
rootdir = get_common_ancestor(dirs)
139180
else:
140181
ancestor = get_common_ancestor(dirs)
141-
rootdir, inifile, inicfg = getcfg([ancestor], config=config)
182+
rootdir, inifile, inicfg = getcfg([ancestor])
142183
if rootdir is None and rootdir_cmd_arg is None:
143184
for possible_rootdir in ancestor.parts(reverse=True):
144185
if possible_rootdir.join("setup.py").exists():
145186
rootdir = possible_rootdir
146187
break
147188
else:
148189
if dirs != [ancestor]:
149-
rootdir, inifile, inicfg = getcfg(dirs, config=config)
190+
rootdir, inifile, inicfg = getcfg(dirs)
150191
if rootdir is None:
151192
if config is not None:
152193
cwd = config.invocation_dir

testing/test_config.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,14 @@ def test_tox_ini_wrong_version(self, testdir):
8282
".ini",
8383
tox="""
8484
[pytest]
85-
minversion=9.0
85+
minversion=999.0
8686
""",
8787
)
8888
result = testdir.runpytest()
8989
assert result.ret != 0
90-
result.stderr.fnmatch_lines(["*tox.ini:2*requires*9.0*actual*"])
90+
result.stderr.fnmatch_lines(
91+
["*tox.ini: 'minversion' requires pytest-999.0, actual pytest-*"]
92+
)
9193

9294
@pytest.mark.parametrize(
9395
"section, name",

0 commit comments

Comments
 (0)