Skip to content

Commit ce7cff9

Browse files
committed
Move pathlist support to legacypath plugin
1 parent d9ca55c commit ce7cff9

File tree

4 files changed

+92
-25
lines changed

4 files changed

+92
-25
lines changed

src/_pytest/config/__init__.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
from _pytest._io import TerminalWriter
5050
from _pytest.compat import final
5151
from _pytest.compat import importlib_metadata
52-
from _pytest.compat import legacy_path
5352
from _pytest.outcomes import fail
5453
from _pytest.outcomes import Skipped
5554
from _pytest.pathlib import absolutepath
@@ -1369,6 +1368,12 @@ def getini(self, name: str):
13691368
self._inicache[name] = val = self._getini(name)
13701369
return val
13711370

1371+
# Meant for easy monkeypatching by legacypath plugin.
1372+
# Can be inlined back (with no cover removed) once legacypath is gone.
1373+
def _getini_unknown_type(self, name: str, type: str, value: Union[str, List[str]]):
1374+
msg = f"unknown configuration type: {type}"
1375+
raise ValueError(msg, value) # pragma: no cover
1376+
13721377
def _getini(self, name: str):
13731378
try:
13741379
description, type, default = self._parser._inidict[name]
@@ -1401,13 +1406,7 @@ def _getini(self, name: str):
14011406
# a_line_list = ["tests", "acceptance"]
14021407
# in this case, we already have a list ready to use.
14031408
#
1404-
if type == "pathlist":
1405-
# TODO: This assert is probably not valid in all cases.
1406-
assert self.inipath is not None
1407-
dp = self.inipath.parent
1408-
input_values = shlex.split(value) if isinstance(value, str) else value
1409-
return [legacy_path(str(dp / x)) for x in input_values]
1410-
elif type == "paths":
1409+
if type == "paths":
14111410
# TODO: This assert is probably not valid in all cases.
14121411
assert self.inipath is not None
14131412
dp = self.inipath.parent
@@ -1422,9 +1421,12 @@ def _getini(self, name: str):
14221421
return value
14231422
elif type == "bool":
14241423
return _strtobool(str(value).strip())
1425-
else:
1426-
assert type in [None, "string"]
1424+
elif type == "string":
14271425
return value
1426+
elif type is None:
1427+
return value
1428+
else:
1429+
return self._getini_unknown_type(name, type, value)
14281430

14291431
def _getconftest_pathlist(
14301432
self, name: str, path: Path, rootpath: Path

src/_pytest/legacypath.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Add backward compatibility support for the legacy py path type."""
2+
import shlex
23
import subprocess
34
from pathlib import Path
45
from typing import List
@@ -372,6 +373,19 @@ def Session_stardir(self: pytest.Session) -> LEGACY_PATH:
372373
return legacy_path(self.startpath)
373374

374375

376+
def Config__getini_unknown_type(
377+
self, name: str, type: str, value: Union[str, List[str]]
378+
):
379+
if type == "pathlist":
380+
# TODO: This assert is probably not valid in all cases.
381+
assert self.inipath is not None
382+
dp = self.inipath.parent
383+
input_values = shlex.split(value) if isinstance(value, str) else value
384+
return [legacy_path(str(dp / x)) for x in input_values]
385+
else:
386+
raise ValueError(f"unknown configuration type: {type}", value)
387+
388+
375389
def pytest_configure(config: pytest.Config) -> None:
376390
mp = pytest.MonkeyPatch()
377391
config.add_cleanup(mp.undo)
@@ -412,3 +426,6 @@ def pytest_configure(config: pytest.Config) -> None:
412426

413427
# Add Session.startdir property.
414428
mp.setattr(pytest.Session, "startdir", property(Session_stardir), raising=False)
429+
430+
# Add pathlist configuration type.
431+
mp.setattr(pytest.Config, "_getini_unknown_type", Config__getini_unknown_type)

testing/test_config.py

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -635,14 +635,11 @@ def pytest_addoption(parser):
635635
pytest.raises(ValueError, config.getini, "other")
636636

637637
@pytest.mark.parametrize("config_type", ["ini", "pyproject"])
638-
@pytest.mark.parametrize("ini_type", ["paths", "pathlist"])
639-
def test_addini_paths(
640-
self, pytester: Pytester, config_type: str, ini_type: str
641-
) -> None:
638+
def test_addini_paths(self, pytester: Pytester, config_type: str) -> None:
642639
pytester.makeconftest(
643-
f"""
640+
"""
644641
def pytest_addoption(parser):
645-
parser.addini("paths", "my new ini value", type="{ini_type}")
642+
parser.addini("paths", "my new ini value", type="paths")
646643
parser.addini("abc", "abc value")
647644
"""
648645
)
@@ -1521,28 +1518,24 @@ def test_pass(pytestconfig):
15211518
assert result.ret == 0
15221519
result.stdout.fnmatch_lines(["custom_option:3.0"])
15231520

1524-
@pytest.mark.parametrize("ini_type", ["paths", "pathlist"])
1525-
def test_override_ini_paths(self, pytester: Pytester, ini_type: str) -> None:
1521+
def test_override_ini_paths(self, pytester: Pytester) -> None:
15261522
pytester.makeconftest(
1527-
f"""
1523+
"""
15281524
def pytest_addoption(parser):
1529-
parser.addini("paths", "my new ini value", type="{ini_type}")"""
1525+
parser.addini("paths", "my new ini value", type="paths")"""
15301526
)
15311527
pytester.makeini(
15321528
"""
15331529
[pytest]
15341530
paths=blah.py"""
15351531
)
15361532
pytester.makepyfile(
1537-
rf"""
1533+
r"""
15381534
def test_overriden(pytestconfig):
15391535
config_paths = pytestconfig.getini("paths")
15401536
print(config_paths)
15411537
for cpf in config_paths:
1542-
if "{ini_type}" == "pathlist":
1543-
print('\nuser_path:%s' % cpf.basename)
1544-
else:
1545-
print('\nuser_path:%s' % cpf.name)
1538+
print('\nuser_path:%s' % cpf.name)
15461539
"""
15471540
)
15481541
result = pytester.runpytest(

testing/test_legacypath.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,58 @@ def test_session_scoped_unavailable_attributes(self, session_request):
9494
match="path not available in session-scoped context",
9595
):
9696
session_request.fspath
97+
98+
99+
@pytest.mark.parametrize("config_type", ["ini", "pyproject"])
100+
def test_addini_paths(pytester: pytest.Pytester, config_type: str) -> None:
101+
pytester.makeconftest(
102+
"""
103+
def pytest_addoption(parser):
104+
parser.addini("paths", "my new ini value", type="pathlist")
105+
parser.addini("abc", "abc value")
106+
"""
107+
)
108+
if config_type == "ini":
109+
inipath = pytester.makeini(
110+
"""
111+
[pytest]
112+
paths=hello world/sub.py
113+
"""
114+
)
115+
elif config_type == "pyproject":
116+
inipath = pytester.makepyprojecttoml(
117+
"""
118+
[tool.pytest.ini_options]
119+
paths=["hello", "world/sub.py"]
120+
"""
121+
)
122+
config = pytester.parseconfig()
123+
values = config.getini("paths")
124+
assert len(values) == 2
125+
assert values[0] == inipath.parent.joinpath("hello")
126+
assert values[1] == inipath.parent.joinpath("world/sub.py")
127+
pytest.raises(ValueError, config.getini, "other")
128+
129+
130+
def test_override_ini_paths(pytester: pytest.Pytester) -> None:
131+
pytester.makeconftest(
132+
"""
133+
def pytest_addoption(parser):
134+
parser.addini("paths", "my new ini value", type="pathlist")"""
135+
)
136+
pytester.makeini(
137+
"""
138+
[pytest]
139+
paths=blah.py"""
140+
)
141+
pytester.makepyfile(
142+
r"""
143+
def test_overriden(pytestconfig):
144+
config_paths = pytestconfig.getini("paths")
145+
print(config_paths)
146+
for cpf in config_paths:
147+
print('\nuser_path:%s' % cpf.basename)
148+
"""
149+
)
150+
result = pytester.runpytest("--override-ini", "paths=foo/bar1.py foo/bar2.py", "-s")
151+
result.stdout.fnmatch_lines(["user_path:bar1.py", "user_path:bar2.py"])

0 commit comments

Comments
 (0)