Skip to content

Commit

Permalink
Move pathlist support to legacypath plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
bluetech committed Oct 28, 2021
1 parent e9c30ca commit 8d52ce3
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 25 deletions.
22 changes: 12 additions & 10 deletions src/_pytest/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
from _pytest._io import TerminalWriter
from _pytest.compat import final
from _pytest.compat import importlib_metadata
from _pytest.compat import legacy_path
from _pytest.outcomes import fail
from _pytest.outcomes import Skipped
from _pytest.pathlib import absolutepath
Expand Down Expand Up @@ -1369,6 +1368,12 @@ def getini(self, name: str):
self._inicache[name] = val = self._getini(name)
return val

# Meant for easy monkeypatching by legacypath plugin.
# Can be inlined back (with no cover removed) once legacypath is gone.
def _getini_unknown_type(self, name: str, type: str, value: Union[str, List[str]]):
msg = f"unknown configuration type: {type}"
raise ValueError(msg, value) # pragma: no cover

def _getini(self, name: str):
try:
description, type, default = self._parser._inidict[name]
Expand Down Expand Up @@ -1401,13 +1406,7 @@ def _getini(self, name: str):
# a_line_list = ["tests", "acceptance"]
# in this case, we already have a list ready to use.
#
if type == "pathlist":
# TODO: This assert is probably not valid in all cases.
assert self.inipath is not None
dp = self.inipath.parent
input_values = shlex.split(value) if isinstance(value, str) else value
return [legacy_path(str(dp / x)) for x in input_values]
elif type == "paths":
if type == "paths":
# TODO: This assert is probably not valid in all cases.
assert self.inipath is not None
dp = self.inipath.parent
Expand All @@ -1422,9 +1421,12 @@ def _getini(self, name: str):
return value
elif type == "bool":
return _strtobool(str(value).strip())
else:
assert type in [None, "string"]
elif type == "string":
return value
elif type is None:
return value
else:
return self._getini_unknown_type(name, type, value)

def _getconftest_pathlist(
self, name: str, path: Path, rootpath: Path
Expand Down
17 changes: 17 additions & 0 deletions src/_pytest/legacypath.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Add backward compatibility support for the legacy py path type."""
import shlex
import subprocess
from pathlib import Path
from typing import List
Expand Down Expand Up @@ -372,6 +373,19 @@ def Session_stardir(self: pytest.Session) -> LEGACY_PATH:
return legacy_path(self.startpath)


def Config__getini_unknown_type(
self, name: str, type: str, value: Union[str, List[str]]
):
if type == "pathlist":
# TODO: This assert is probably not valid in all cases.
assert self.inipath is not None
dp = self.inipath.parent
input_values = shlex.split(value) if isinstance(value, str) else value
return [legacy_path(str(dp / x)) for x in input_values]
else:
raise ValueError(f"unknown configuration type: {type}", value)


def pytest_configure(config: pytest.Config) -> None:
mp = pytest.MonkeyPatch()
config.add_cleanup(mp.undo)
Expand Down Expand Up @@ -412,3 +426,6 @@ def pytest_configure(config: pytest.Config) -> None:

# Add Session.startdir property.
mp.setattr(pytest.Session, "startdir", property(Session_stardir), raising=False)

# Add pathlist configuration type.
mp.setattr(pytest.Config, "_getini_unknown_type", Config__getini_unknown_type)
23 changes: 8 additions & 15 deletions testing/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,14 +635,11 @@ def pytest_addoption(parser):
pytest.raises(ValueError, config.getini, "other")

@pytest.mark.parametrize("config_type", ["ini", "pyproject"])
@pytest.mark.parametrize("ini_type", ["paths", "pathlist"])
def test_addini_paths(
self, pytester: Pytester, config_type: str, ini_type: str
) -> None:
def test_addini_paths(self, pytester: Pytester, config_type: str) -> None:
pytester.makeconftest(
f"""
"""
def pytest_addoption(parser):
parser.addini("paths", "my new ini value", type="{ini_type}")
parser.addini("paths", "my new ini value", type="paths")
parser.addini("abc", "abc value")
"""
)
Expand Down Expand Up @@ -1521,28 +1518,24 @@ def test_pass(pytestconfig):
assert result.ret == 0
result.stdout.fnmatch_lines(["custom_option:3.0"])

@pytest.mark.parametrize("ini_type", ["paths", "pathlist"])
def test_override_ini_paths(self, pytester: Pytester, ini_type: str) -> None:
def test_override_ini_paths(self, pytester: Pytester) -> None:
pytester.makeconftest(
f"""
"""
def pytest_addoption(parser):
parser.addini("paths", "my new ini value", type="{ini_type}")"""
parser.addini("paths", "my new ini value", type="paths")"""
)
pytester.makeini(
"""
[pytest]
paths=blah.py"""
)
pytester.makepyfile(
rf"""
r"""
def test_overriden(pytestconfig):
config_paths = pytestconfig.getini("paths")
print(config_paths)
for cpf in config_paths:
if "{ini_type}" == "pathlist":
print('\nuser_path:%s' % cpf.basename)
else:
print('\nuser_path:%s' % cpf.name)
print('\nuser_path:%s' % cpf.name)
"""
)
result = pytester.runpytest(
Expand Down
55 changes: 55 additions & 0 deletions testing/test_legacypath.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,58 @@ def test_session_scoped_unavailable_attributes(self, session_request):
match="path not available in session-scoped context",
):
session_request.fspath


@pytest.mark.parametrize("config_type", ["ini", "pyproject"])
def test_addini_paths(pytester: pytest.Pytester, config_type: str) -> None:
pytester.makeconftest(
"""
def pytest_addoption(parser):
parser.addini("paths", "my new ini value", type="pathlist")
parser.addini("abc", "abc value")
"""
)
if config_type == "ini":
inipath = pytester.makeini(
"""
[pytest]
paths=hello world/sub.py
"""
)
elif config_type == "pyproject":
inipath = pytester.makepyprojecttoml(
"""
[tool.pytest.ini_options]
paths=["hello", "world/sub.py"]
"""
)
config = pytester.parseconfig()
values = config.getini("paths")
assert len(values) == 2
assert values[0] == inipath.parent.joinpath("hello")
assert values[1] == inipath.parent.joinpath("world/sub.py")
pytest.raises(ValueError, config.getini, "other")


def test_override_ini_paths(pytester: pytest.Pytester) -> None:
pytester.makeconftest(
"""
def pytest_addoption(parser):
parser.addini("paths", "my new ini value", type="pathlist")"""
)
pytester.makeini(
"""
[pytest]
paths=blah.py"""
)
pytester.makepyfile(
r"""
def test_overriden(pytestconfig):
config_paths = pytestconfig.getini("paths")
print(config_paths)
for cpf in config_paths:
print('\nuser_path:%s' % cpf.basename)
"""
)
result = pytester.runpytest("--override-ini", "paths=foo/bar1.py foo/bar2.py", "-s")
result.stdout.fnmatch_lines(["user_path:bar1.py", "user_path:bar2.py"])

0 comments on commit 8d52ce3

Please sign in to comment.