config/findpaths: convert from py.path.local to pathlib
This commit is contained in:
parent
9e55288ba4
commit
70f3ad1c1f
|
@ -1006,12 +1006,15 @@ class Config:
|
|||
ns, unknown_args = self._parser.parse_known_and_unknown_args(
|
||||
args, namespace=copy.copy(self.option)
|
||||
)
|
||||
self.rootdir, self.inifile, self.inicfg = determine_setup(
|
||||
rootpath, inipath, inicfg = determine_setup(
|
||||
ns.inifilename,
|
||||
ns.file_or_dir + unknown_args,
|
||||
rootdir_cmd_arg=ns.rootdir or None,
|
||||
config=self,
|
||||
)
|
||||
self.rootdir = py.path.local(str(rootpath))
|
||||
self.inifile = py.path.local(str(inipath)) if inipath else None
|
||||
self.inicfg = inicfg
|
||||
self._parser.extra_info["rootdir"] = self.rootdir
|
||||
self._parser.extra_info["inifile"] = self.inifile
|
||||
self._parser.addini("addopts", "extra command line options", "args")
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
import itertools
|
||||
import os
|
||||
import sys
|
||||
from typing import Dict
|
||||
from typing import Iterable
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Sequence
|
||||
from typing import Tuple
|
||||
from typing import Union
|
||||
|
||||
import iniconfig
|
||||
import py
|
||||
|
||||
from .exceptions import UsageError
|
||||
from _pytest.compat import TYPE_CHECKING
|
||||
from _pytest.outcomes import fail
|
||||
from _pytest.pathlib import absolutepath
|
||||
from _pytest.pathlib import commonpath
|
||||
from _pytest.pathlib import Path
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import Config
|
||||
|
||||
|
||||
def _parse_ini_config(path: py.path.local) -> iniconfig.IniConfig:
|
||||
def _parse_ini_config(path: Path) -> iniconfig.IniConfig:
|
||||
"""Parse the given generic '.ini' file using legacy IniConfig parser, returning
|
||||
the parsed object.
|
||||
|
||||
|
@ -30,7 +35,7 @@ def _parse_ini_config(path: py.path.local) -> iniconfig.IniConfig:
|
|||
|
||||
|
||||
def load_config_dict_from_file(
|
||||
filepath: py.path.local,
|
||||
filepath: Path,
|
||||
) -> Optional[Dict[str, Union[str, List[str]]]]:
|
||||
"""Load pytest configuration from the given file path, if supported.
|
||||
|
||||
|
@ -38,18 +43,18 @@ def load_config_dict_from_file(
|
|||
"""
|
||||
|
||||
# Configuration from ini files are obtained from the [pytest] section, if present.
|
||||
if filepath.ext == ".ini":
|
||||
if filepath.suffix == ".ini":
|
||||
iniconfig = _parse_ini_config(filepath)
|
||||
|
||||
if "pytest" in iniconfig:
|
||||
return dict(iniconfig["pytest"].items())
|
||||
else:
|
||||
# "pytest.ini" files are always the source of configuration, even if empty.
|
||||
if filepath.basename == "pytest.ini":
|
||||
if filepath.name == "pytest.ini":
|
||||
return {}
|
||||
|
||||
# '.cfg' files are considered if they contain a "[tool:pytest]" section.
|
||||
elif filepath.ext == ".cfg":
|
||||
elif filepath.suffix == ".cfg":
|
||||
iniconfig = _parse_ini_config(filepath)
|
||||
|
||||
if "tool:pytest" in iniconfig.sections:
|
||||
|
@ -60,7 +65,7 @@ def load_config_dict_from_file(
|
|||
fail(CFG_PYTEST_SECTION.format(filename="setup.cfg"), pytrace=False)
|
||||
|
||||
# '.toml' files are considered if they contain a [tool.pytest.ini_options] table.
|
||||
elif filepath.ext == ".toml":
|
||||
elif filepath.suffix == ".toml":
|
||||
import toml
|
||||
|
||||
config = toml.load(str(filepath))
|
||||
|
@ -79,9 +84,9 @@ def load_config_dict_from_file(
|
|||
|
||||
|
||||
def locate_config(
|
||||
args: Iterable[Union[str, py.path.local]]
|
||||
args: Iterable[Path],
|
||||
) -> Tuple[
|
||||
Optional[py.path.local], Optional[py.path.local], Dict[str, Union[str, List[str]]],
|
||||
Optional[Path], Optional[Path], Dict[str, Union[str, List[str]]],
|
||||
]:
|
||||
"""Search in the list of arguments for a valid ini-file for pytest,
|
||||
and return a tuple of (rootdir, inifile, cfg-dict)."""
|
||||
|
@ -93,62 +98,77 @@ def locate_config(
|
|||
]
|
||||
args = [x for x in args if not str(x).startswith("-")]
|
||||
if not args:
|
||||
args = [py.path.local()]
|
||||
args = [Path.cwd()]
|
||||
for arg in args:
|
||||
arg = py.path.local(arg)
|
||||
for base in arg.parts(reverse=True):
|
||||
argpath = absolutepath(arg)
|
||||
for base in itertools.chain((argpath,), reversed(argpath.parents)):
|
||||
for config_name in config_names:
|
||||
p = base.join(config_name)
|
||||
if p.isfile():
|
||||
p = base / config_name
|
||||
if p.is_file():
|
||||
ini_config = load_config_dict_from_file(p)
|
||||
if ini_config is not None:
|
||||
return base, p, ini_config
|
||||
return None, None, {}
|
||||
|
||||
|
||||
def get_common_ancestor(paths: Iterable[py.path.local]) -> py.path.local:
|
||||
common_ancestor = None # type: Optional[py.path.local]
|
||||
def get_common_ancestor(paths: Iterable[Path]) -> Path:
|
||||
common_ancestor = None # type: Optional[Path]
|
||||
for path in paths:
|
||||
if not path.exists():
|
||||
continue
|
||||
if common_ancestor is None:
|
||||
common_ancestor = path
|
||||
else:
|
||||
if path.relto(common_ancestor) or path == common_ancestor:
|
||||
if common_ancestor in path.parents or path == common_ancestor:
|
||||
continue
|
||||
elif common_ancestor.relto(path):
|
||||
elif path in common_ancestor.parents:
|
||||
common_ancestor = path
|
||||
else:
|
||||
shared = path.common(common_ancestor)
|
||||
shared = commonpath(path, common_ancestor)
|
||||
if shared is not None:
|
||||
common_ancestor = shared
|
||||
if common_ancestor is None:
|
||||
common_ancestor = py.path.local()
|
||||
elif common_ancestor.isfile():
|
||||
common_ancestor = common_ancestor.dirpath()
|
||||
common_ancestor = Path.cwd()
|
||||
elif common_ancestor.is_file():
|
||||
common_ancestor = common_ancestor.parent
|
||||
return common_ancestor
|
||||
|
||||
|
||||
def get_dirs_from_args(args: Iterable[str]) -> List[py.path.local]:
|
||||
def get_dirs_from_args(args: Iterable[str]) -> List[Path]:
|
||||
def is_option(x: str) -> bool:
|
||||
return x.startswith("-")
|
||||
|
||||
def get_file_part_from_node_id(x: str) -> str:
|
||||
return x.split("::")[0]
|
||||
|
||||
def get_dir_from_path(path: py.path.local) -> py.path.local:
|
||||
if path.isdir():
|
||||
def get_dir_from_path(path: Path) -> Path:
|
||||
if path.is_dir():
|
||||
return path
|
||||
return py.path.local(path.dirname)
|
||||
return path.parent
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
|
||||
def safe_exists(path: Path) -> bool:
|
||||
# On Python<3.8, this can throw on paths that contain characters
|
||||
# unrepresentable at the OS level.
|
||||
try:
|
||||
return path.exists()
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
else:
|
||||
|
||||
def safe_exists(path: Path) -> bool:
|
||||
return path.exists()
|
||||
|
||||
# These look like paths but may not exist
|
||||
possible_paths = (
|
||||
py.path.local(get_file_part_from_node_id(arg))
|
||||
absolutepath(get_file_part_from_node_id(arg))
|
||||
for arg in args
|
||||
if not is_option(arg)
|
||||
)
|
||||
|
||||
return [get_dir_from_path(path) for path in possible_paths if path.exists()]
|
||||
return [get_dir_from_path(path) for path in possible_paths if safe_exists(path)]
|
||||
|
||||
|
||||
CFG_PYTEST_SECTION = "[pytest] section in {filename} files is no longer supported, change to [tool:pytest] instead."
|
||||
|
@ -156,15 +176,15 @@ CFG_PYTEST_SECTION = "[pytest] section in {filename} files is no longer supporte
|
|||
|
||||
def determine_setup(
|
||||
inifile: Optional[str],
|
||||
args: List[str],
|
||||
args: Sequence[str],
|
||||
rootdir_cmd_arg: Optional[str] = None,
|
||||
config: Optional["Config"] = None,
|
||||
) -> Tuple[py.path.local, Optional[py.path.local], Dict[str, Union[str, List[str]]]]:
|
||||
) -> Tuple[Path, Optional[Path], Dict[str, Union[str, List[str]]]]:
|
||||
rootdir = None
|
||||
dirs = get_dirs_from_args(args)
|
||||
if inifile:
|
||||
inipath_ = py.path.local(inifile)
|
||||
inipath = inipath_ # type: Optional[py.path.local]
|
||||
inipath_ = absolutepath(inifile)
|
||||
inipath = inipath_ # type: Optional[Path]
|
||||
inicfg = load_config_dict_from_file(inipath_) or {}
|
||||
if rootdir_cmd_arg is None:
|
||||
rootdir = get_common_ancestor(dirs)
|
||||
|
@ -172,8 +192,10 @@ def determine_setup(
|
|||
ancestor = get_common_ancestor(dirs)
|
||||
rootdir, inipath, inicfg = locate_config([ancestor])
|
||||
if rootdir is None and rootdir_cmd_arg is None:
|
||||
for possible_rootdir in ancestor.parts(reverse=True):
|
||||
if possible_rootdir.join("setup.py").exists():
|
||||
for possible_rootdir in itertools.chain(
|
||||
(ancestor,), reversed(ancestor.parents)
|
||||
):
|
||||
if (possible_rootdir / "setup.py").is_file():
|
||||
rootdir = possible_rootdir
|
||||
break
|
||||
else:
|
||||
|
@ -181,16 +203,16 @@ def determine_setup(
|
|||
rootdir, inipath, inicfg = locate_config(dirs)
|
||||
if rootdir is None:
|
||||
if config is not None:
|
||||
cwd = config.invocation_dir
|
||||
cwd = config.invocation_params.dir
|
||||
else:
|
||||
cwd = py.path.local()
|
||||
cwd = Path.cwd()
|
||||
rootdir = get_common_ancestor([cwd, ancestor])
|
||||
is_fs_root = os.path.splitdrive(str(rootdir))[1] == "/"
|
||||
if is_fs_root:
|
||||
rootdir = ancestor
|
||||
if rootdir_cmd_arg:
|
||||
rootdir = py.path.local(os.path.expandvars(rootdir_cmd_arg))
|
||||
if not rootdir.isdir():
|
||||
rootdir = absolutepath(os.path.expandvars(rootdir_cmd_arg))
|
||||
if not rootdir.is_dir():
|
||||
raise UsageError(
|
||||
"Directory '{}' not found. Check your '--rootdir' option.".format(
|
||||
rootdir
|
||||
|
|
|
@ -21,17 +21,27 @@ from _pytest.config.exceptions import UsageError
|
|||
from _pytest.config.findpaths import determine_setup
|
||||
from _pytest.config.findpaths import get_common_ancestor
|
||||
from _pytest.config.findpaths import locate_config
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
from _pytest.pathlib import Path
|
||||
from _pytest.pytester import Testdir
|
||||
|
||||
|
||||
class TestParseIni:
|
||||
@pytest.mark.parametrize(
|
||||
"section, filename", [("pytest", "pytest.ini"), ("tool:pytest", "setup.cfg")]
|
||||
)
|
||||
def test_getcfg_and_config(self, testdir, tmpdir, section, filename):
|
||||
sub = tmpdir.mkdir("sub")
|
||||
sub.chdir()
|
||||
tmpdir.join(filename).write(
|
||||
def test_getcfg_and_config(
|
||||
self,
|
||||
testdir: Testdir,
|
||||
tmp_path: Path,
|
||||
section: str,
|
||||
filename: str,
|
||||
monkeypatch: MonkeyPatch,
|
||||
) -> None:
|
||||
sub = tmp_path / "sub"
|
||||
sub.mkdir()
|
||||
monkeypatch.chdir(sub)
|
||||
(tmp_path / filename).write_text(
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
[{section}]
|
||||
|
@ -39,17 +49,14 @@ class TestParseIni:
|
|||
""".format(
|
||||
section=section
|
||||
)
|
||||
)
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
_, _, cfg = locate_config([sub])
|
||||
assert cfg["name"] == "value"
|
||||
config = testdir.parseconfigure(sub)
|
||||
config = testdir.parseconfigure(str(sub))
|
||||
assert config.inicfg["name"] == "value"
|
||||
|
||||
def test_getcfg_empty_path(self):
|
||||
"""Correctly handle zero length arguments (a la pytest '')."""
|
||||
locate_config([""])
|
||||
|
||||
def test_setupcfg_uses_toolpytest_with_pytest(self, testdir):
|
||||
p1 = testdir.makepyfile("def test(): pass")
|
||||
testdir.makefile(
|
||||
|
@ -1168,16 +1175,17 @@ def test_collect_pytest_prefix_bug(pytestconfig):
|
|||
|
||||
|
||||
class TestRootdir:
|
||||
def test_simple_noini(self, tmpdir):
|
||||
assert get_common_ancestor([tmpdir]) == tmpdir
|
||||
a = tmpdir.mkdir("a")
|
||||
assert get_common_ancestor([a, tmpdir]) == tmpdir
|
||||
assert get_common_ancestor([tmpdir, a]) == tmpdir
|
||||
with tmpdir.as_cwd():
|
||||
assert get_common_ancestor([]) == tmpdir
|
||||
no_path = tmpdir.join("does-not-exist")
|
||||
assert get_common_ancestor([no_path]) == tmpdir
|
||||
assert get_common_ancestor([no_path.join("a")]) == tmpdir
|
||||
def test_simple_noini(self, tmp_path: Path, monkeypatch: MonkeyPatch) -> None:
|
||||
assert get_common_ancestor([tmp_path]) == tmp_path
|
||||
a = tmp_path / "a"
|
||||
a.mkdir()
|
||||
assert get_common_ancestor([a, tmp_path]) == tmp_path
|
||||
assert get_common_ancestor([tmp_path, a]) == tmp_path
|
||||
monkeypatch.chdir(tmp_path)
|
||||
assert get_common_ancestor([]) == tmp_path
|
||||
no_path = tmp_path / "does-not-exist"
|
||||
assert get_common_ancestor([no_path]) == tmp_path
|
||||
assert get_common_ancestor([no_path / "a"]) == tmp_path
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"name, contents",
|
||||
|
@ -1190,44 +1198,49 @@ class TestRootdir:
|
|||
pytest.param("setup.cfg", "[tool:pytest]\nx=10", id="setup.cfg"),
|
||||
],
|
||||
)
|
||||
def test_with_ini(self, tmpdir: py.path.local, name: str, contents: str) -> None:
|
||||
inifile = tmpdir.join(name)
|
||||
inifile.write(contents)
|
||||
def test_with_ini(self, tmp_path: Path, name: str, contents: str) -> None:
|
||||
inipath = tmp_path / name
|
||||
inipath.write_text(contents, "utf-8")
|
||||
|
||||
a = tmpdir.mkdir("a")
|
||||
b = a.mkdir("b")
|
||||
for args in ([str(tmpdir)], [str(a)], [str(b)]):
|
||||
rootdir, parsed_inifile, _ = determine_setup(None, args)
|
||||
assert rootdir == tmpdir
|
||||
assert parsed_inifile == inifile
|
||||
rootdir, parsed_inifile, ini_config = determine_setup(None, [str(b), str(a)])
|
||||
assert rootdir == tmpdir
|
||||
assert parsed_inifile == inifile
|
||||
a = tmp_path / "a"
|
||||
a.mkdir()
|
||||
b = a / "b"
|
||||
b.mkdir()
|
||||
for args in ([str(tmp_path)], [str(a)], [str(b)]):
|
||||
rootpath, parsed_inipath, _ = determine_setup(None, args)
|
||||
assert rootpath == tmp_path
|
||||
assert parsed_inipath == inipath
|
||||
rootpath, parsed_inipath, ini_config = determine_setup(None, [str(b), str(a)])
|
||||
assert rootpath == tmp_path
|
||||
assert parsed_inipath == inipath
|
||||
assert ini_config == {"x": "10"}
|
||||
|
||||
@pytest.mark.parametrize("name", "setup.cfg tox.ini".split())
|
||||
def test_pytestini_overrides_empty_other(self, tmpdir: py.path.local, name) -> None:
|
||||
inifile = tmpdir.ensure("pytest.ini")
|
||||
a = tmpdir.mkdir("a")
|
||||
a.ensure(name)
|
||||
rootdir, parsed_inifile, _ = determine_setup(None, [str(a)])
|
||||
assert rootdir == tmpdir
|
||||
assert parsed_inifile == inifile
|
||||
@pytest.mark.parametrize("name", ["setup.cfg", "tox.ini"])
|
||||
def test_pytestini_overrides_empty_other(self, tmp_path: Path, name: str) -> None:
|
||||
inipath = tmp_path / "pytest.ini"
|
||||
inipath.touch()
|
||||
a = tmp_path / "a"
|
||||
a.mkdir()
|
||||
(a / name).touch()
|
||||
rootpath, parsed_inipath, _ = determine_setup(None, [str(a)])
|
||||
assert rootpath == tmp_path
|
||||
assert parsed_inipath == inipath
|
||||
|
||||
def test_setuppy_fallback(self, tmpdir: py.path.local) -> None:
|
||||
a = tmpdir.mkdir("a")
|
||||
a.ensure("setup.cfg")
|
||||
tmpdir.ensure("setup.py")
|
||||
rootdir, inifile, inicfg = determine_setup(None, [str(a)])
|
||||
assert rootdir == tmpdir
|
||||
assert inifile is None
|
||||
def test_setuppy_fallback(self, tmp_path: Path) -> None:
|
||||
a = tmp_path / "a"
|
||||
a.mkdir()
|
||||
(a / "setup.cfg").touch()
|
||||
(tmp_path / "setup.py").touch()
|
||||
rootpath, inipath, inicfg = determine_setup(None, [str(a)])
|
||||
assert rootpath == tmp_path
|
||||
assert inipath is None
|
||||
assert inicfg == {}
|
||||
|
||||
def test_nothing(self, tmpdir: py.path.local, monkeypatch) -> None:
|
||||
monkeypatch.chdir(str(tmpdir))
|
||||
rootdir, inifile, inicfg = determine_setup(None, [str(tmpdir)])
|
||||
assert rootdir == tmpdir
|
||||
assert inifile is None
|
||||
def test_nothing(self, tmp_path: Path, monkeypatch: MonkeyPatch) -> None:
|
||||
monkeypatch.chdir(tmp_path)
|
||||
rootpath, inipath, inicfg = determine_setup(None, [str(tmp_path)])
|
||||
assert rootpath == tmp_path
|
||||
assert inipath is None
|
||||
assert inicfg == {}
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -1242,45 +1255,58 @@ class TestRootdir:
|
|||
],
|
||||
)
|
||||
def test_with_specific_inifile(
|
||||
self, tmpdir: py.path.local, name: str, contents: str
|
||||
self, tmp_path: Path, name: str, contents: str
|
||||
) -> None:
|
||||
p = tmpdir.ensure(name)
|
||||
p.write(contents)
|
||||
rootdir, inifile, ini_config = determine_setup(str(p), [str(tmpdir)])
|
||||
assert rootdir == tmpdir
|
||||
assert inifile == p
|
||||
p = tmp_path / name
|
||||
p.touch()
|
||||
p.write_text(contents, "utf-8")
|
||||
rootpath, inipath, ini_config = determine_setup(str(p), [str(tmp_path)])
|
||||
assert rootpath == tmp_path
|
||||
assert inipath == p
|
||||
assert ini_config == {"x": "10"}
|
||||
|
||||
def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch) -> None:
|
||||
monkeypatch.chdir(str(tmpdir))
|
||||
a = tmpdir.mkdir("a")
|
||||
b = tmpdir.mkdir("b")
|
||||
rootdir, inifile, _ = determine_setup(None, [str(a), str(b)])
|
||||
assert rootdir == tmpdir
|
||||
def test_with_arg_outside_cwd_without_inifile(
|
||||
self, tmp_path: Path, monkeypatch: MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.chdir(tmp_path)
|
||||
a = tmp_path / "a"
|
||||
a.mkdir()
|
||||
b = tmp_path / "b"
|
||||
b.mkdir()
|
||||
rootpath, inifile, _ = determine_setup(None, [str(a), str(b)])
|
||||
assert rootpath == tmp_path
|
||||
assert inifile is None
|
||||
|
||||
def test_with_arg_outside_cwd_with_inifile(self, tmpdir) -> None:
|
||||
a = tmpdir.mkdir("a")
|
||||
b = tmpdir.mkdir("b")
|
||||
inifile = a.ensure("pytest.ini")
|
||||
rootdir, parsed_inifile, _ = determine_setup(None, [str(a), str(b)])
|
||||
assert rootdir == a
|
||||
assert inifile == parsed_inifile
|
||||
def test_with_arg_outside_cwd_with_inifile(self, tmp_path: Path) -> None:
|
||||
a = tmp_path / "a"
|
||||
a.mkdir()
|
||||
b = tmp_path / "b"
|
||||
b.mkdir()
|
||||
inipath = a / "pytest.ini"
|
||||
inipath.touch()
|
||||
rootpath, parsed_inipath, _ = determine_setup(None, [str(a), str(b)])
|
||||
assert rootpath == a
|
||||
assert inipath == parsed_inipath
|
||||
|
||||
@pytest.mark.parametrize("dirs", ([], ["does-not-exist"], ["a/does-not-exist"]))
|
||||
def test_with_non_dir_arg(self, dirs, tmpdir) -> None:
|
||||
with tmpdir.ensure(dir=True).as_cwd():
|
||||
rootdir, inifile, _ = determine_setup(None, dirs)
|
||||
assert rootdir == tmpdir
|
||||
assert inifile is None
|
||||
def test_with_non_dir_arg(
|
||||
self, dirs: Sequence[str], tmp_path: Path, monkeypatch: MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.chdir(tmp_path)
|
||||
rootpath, inipath, _ = determine_setup(None, dirs)
|
||||
assert rootpath == tmp_path
|
||||
assert inipath is None
|
||||
|
||||
def test_with_existing_file_in_subdir(self, tmpdir) -> None:
|
||||
a = tmpdir.mkdir("a")
|
||||
a.ensure("exist")
|
||||
with tmpdir.as_cwd():
|
||||
rootdir, inifile, _ = determine_setup(None, ["a/exist"])
|
||||
assert rootdir == tmpdir
|
||||
assert inifile is None
|
||||
def test_with_existing_file_in_subdir(
|
||||
self, tmp_path: Path, monkeypatch: MonkeyPatch
|
||||
) -> None:
|
||||
a = tmp_path / "a"
|
||||
a.mkdir()
|
||||
(a / "exists").touch()
|
||||
monkeypatch.chdir(tmp_path)
|
||||
rootpath, inipath, _ = determine_setup(None, ["a/exist"])
|
||||
assert rootpath == tmp_path
|
||||
assert inipath is None
|
||||
|
||||
|
||||
class TestOverrideIniArgs:
|
||||
|
|
|
@ -1,74 +1,74 @@
|
|||
from textwrap import dedent
|
||||
|
||||
import py
|
||||
|
||||
import pytest
|
||||
from _pytest.config.findpaths import get_common_ancestor
|
||||
from _pytest.config.findpaths import load_config_dict_from_file
|
||||
from _pytest.pathlib import Path
|
||||
|
||||
|
||||
class TestLoadConfigDictFromFile:
|
||||
def test_empty_pytest_ini(self, tmpdir):
|
||||
def test_empty_pytest_ini(self, tmp_path: Path) -> None:
|
||||
"""pytest.ini files are always considered for configuration, even if empty"""
|
||||
fn = tmpdir.join("pytest.ini")
|
||||
fn.write("")
|
||||
fn = tmp_path / "pytest.ini"
|
||||
fn.write_text("", encoding="utf-8")
|
||||
assert load_config_dict_from_file(fn) == {}
|
||||
|
||||
def test_pytest_ini(self, tmpdir):
|
||||
def test_pytest_ini(self, tmp_path: Path) -> None:
|
||||
"""[pytest] section in pytest.ini files is read correctly"""
|
||||
fn = tmpdir.join("pytest.ini")
|
||||
fn.write("[pytest]\nx=1")
|
||||
fn = tmp_path / "pytest.ini"
|
||||
fn.write_text("[pytest]\nx=1", encoding="utf-8")
|
||||
assert load_config_dict_from_file(fn) == {"x": "1"}
|
||||
|
||||
def test_custom_ini(self, tmpdir):
|
||||
def test_custom_ini(self, tmp_path: Path) -> None:
|
||||
"""[pytest] section in any .ini file is read correctly"""
|
||||
fn = tmpdir.join("custom.ini")
|
||||
fn.write("[pytest]\nx=1")
|
||||
fn = tmp_path / "custom.ini"
|
||||
fn.write_text("[pytest]\nx=1", encoding="utf-8")
|
||||
assert load_config_dict_from_file(fn) == {"x": "1"}
|
||||
|
||||
def test_custom_ini_without_section(self, tmpdir):
|
||||
def test_custom_ini_without_section(self, tmp_path: Path) -> None:
|
||||
"""Custom .ini files without [pytest] section are not considered for configuration"""
|
||||
fn = tmpdir.join("custom.ini")
|
||||
fn.write("[custom]")
|
||||
fn = tmp_path / "custom.ini"
|
||||
fn.write_text("[custom]", encoding="utf-8")
|
||||
assert load_config_dict_from_file(fn) is None
|
||||
|
||||
def test_custom_cfg_file(self, tmpdir):
|
||||
def test_custom_cfg_file(self, tmp_path: Path) -> None:
|
||||
"""Custom .cfg files without [tool:pytest] section are not considered for configuration"""
|
||||
fn = tmpdir.join("custom.cfg")
|
||||
fn.write("[custom]")
|
||||
fn = tmp_path / "custom.cfg"
|
||||
fn.write_text("[custom]", encoding="utf-8")
|
||||
assert load_config_dict_from_file(fn) is None
|
||||
|
||||
def test_valid_cfg_file(self, tmpdir):
|
||||
def test_valid_cfg_file(self, tmp_path: Path) -> None:
|
||||
"""Custom .cfg files with [tool:pytest] section are read correctly"""
|
||||
fn = tmpdir.join("custom.cfg")
|
||||
fn.write("[tool:pytest]\nx=1")
|
||||
fn = tmp_path / "custom.cfg"
|
||||
fn.write_text("[tool:pytest]\nx=1", encoding="utf-8")
|
||||
assert load_config_dict_from_file(fn) == {"x": "1"}
|
||||
|
||||
def test_unsupported_pytest_section_in_cfg_file(self, tmpdir):
|
||||
def test_unsupported_pytest_section_in_cfg_file(self, tmp_path: Path) -> None:
|
||||
""".cfg files with [pytest] section are no longer supported and should fail to alert users"""
|
||||
fn = tmpdir.join("custom.cfg")
|
||||
fn.write("[pytest]")
|
||||
fn = tmp_path / "custom.cfg"
|
||||
fn.write_text("[pytest]", encoding="utf-8")
|
||||
with pytest.raises(pytest.fail.Exception):
|
||||
load_config_dict_from_file(fn)
|
||||
|
||||
def test_invalid_toml_file(self, tmpdir):
|
||||
def test_invalid_toml_file(self, tmp_path: Path) -> None:
|
||||
""".toml files without [tool.pytest.ini_options] are not considered for configuration."""
|
||||
fn = tmpdir.join("myconfig.toml")
|
||||
fn.write(
|
||||
fn = tmp_path / "myconfig.toml"
|
||||
fn.write_text(
|
||||
dedent(
|
||||
"""
|
||||
[build_system]
|
||||
x = 1
|
||||
"""
|
||||
)
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
assert load_config_dict_from_file(fn) is None
|
||||
|
||||
def test_valid_toml_file(self, tmpdir):
|
||||
def test_valid_toml_file(self, tmp_path: Path) -> None:
|
||||
""".toml files with [tool.pytest.ini_options] are read correctly, including changing
|
||||
data types to str/list for compatibility with other configuration options."""
|
||||
fn = tmpdir.join("myconfig.toml")
|
||||
fn.write(
|
||||
fn = tmp_path / "myconfig.toml"
|
||||
fn.write_text(
|
||||
dedent(
|
||||
"""
|
||||
[tool.pytest.ini_options]
|
||||
|
@ -77,7 +77,8 @@ class TestLoadConfigDictFromFile:
|
|||
values = ["tests", "integration"]
|
||||
name = "foo"
|
||||
"""
|
||||
)
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
assert load_config_dict_from_file(fn) == {
|
||||
"x": "1",
|
||||
|
@ -88,23 +89,22 @@ class TestLoadConfigDictFromFile:
|
|||
|
||||
|
||||
class TestCommonAncestor:
|
||||
def test_has_ancestor(self, tmpdir):
|
||||
fn1 = tmpdir.join("foo/bar/test_1.py").ensure(file=1)
|
||||
fn2 = tmpdir.join("foo/zaz/test_2.py").ensure(file=1)
|
||||
assert get_common_ancestor([fn1, fn2]) == tmpdir.join("foo")
|
||||
assert get_common_ancestor([py.path.local(fn1.dirname), fn2]) == tmpdir.join(
|
||||
"foo"
|
||||
)
|
||||
assert get_common_ancestor(
|
||||
[py.path.local(fn1.dirname), py.path.local(fn2.dirname)]
|
||||
) == tmpdir.join("foo")
|
||||
assert get_common_ancestor([fn1, py.path.local(fn2.dirname)]) == tmpdir.join(
|
||||
"foo"
|
||||
)
|
||||
def test_has_ancestor(self, tmp_path: Path) -> None:
|
||||
fn1 = tmp_path / "foo" / "bar" / "test_1.py"
|
||||
fn1.parent.mkdir(parents=True)
|
||||
fn1.touch()
|
||||
fn2 = tmp_path / "foo" / "zaz" / "test_2.py"
|
||||
fn2.parent.mkdir(parents=True)
|
||||
fn2.touch()
|
||||
assert get_common_ancestor([fn1, fn2]) == tmp_path / "foo"
|
||||
assert get_common_ancestor([fn1.parent, fn2]) == tmp_path / "foo"
|
||||
assert get_common_ancestor([fn1.parent, fn2.parent]) == tmp_path / "foo"
|
||||
assert get_common_ancestor([fn1, fn2.parent]) == tmp_path / "foo"
|
||||
|
||||
def test_single_dir(self, tmpdir):
|
||||
assert get_common_ancestor([tmpdir]) == tmpdir
|
||||
def test_single_dir(self, tmp_path: Path) -> None:
|
||||
assert get_common_ancestor([tmp_path]) == tmp_path
|
||||
|
||||
def test_single_file(self, tmpdir):
|
||||
fn = tmpdir.join("foo.py").ensure(file=1)
|
||||
assert get_common_ancestor([fn]) == tmpdir
|
||||
def test_single_file(self, tmp_path: Path) -> None:
|
||||
fn = tmp_path / "foo.py"
|
||||
fn.touch()
|
||||
assert get_common_ancestor([fn]) == tmp_path
|
||||
|
|
Loading…
Reference in New Issue