Some py.path.local -> pathlib.Path
- Some conftest related functions - _confcutdir - Allow arbitrary os.PathLike[str] in gethookproxy.
This commit is contained in:
parent
902739cfc3
commit
ed658d6829
|
@ -50,9 +50,11 @@ from _pytest.compat import final
|
||||||
from _pytest.compat import importlib_metadata
|
from _pytest.compat import importlib_metadata
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
from _pytest.outcomes import Skipped
|
from _pytest.outcomes import Skipped
|
||||||
|
from _pytest.pathlib import absolutepath
|
||||||
from _pytest.pathlib import bestrelpath
|
from _pytest.pathlib import bestrelpath
|
||||||
from _pytest.pathlib import import_path
|
from _pytest.pathlib import import_path
|
||||||
from _pytest.pathlib import ImportMode
|
from _pytest.pathlib import ImportMode
|
||||||
|
from _pytest.pathlib import resolve_package_path
|
||||||
from _pytest.store import Store
|
from _pytest.store import Store
|
||||||
from _pytest.warning_types import PytestConfigWarning
|
from _pytest.warning_types import PytestConfigWarning
|
||||||
|
|
||||||
|
@ -102,9 +104,7 @@ class ExitCode(enum.IntEnum):
|
||||||
|
|
||||||
class ConftestImportFailure(Exception):
|
class ConftestImportFailure(Exception):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self, path: Path, excinfo: Tuple[Type[Exception], Exception, TracebackType],
|
||||||
path: py.path.local,
|
|
||||||
excinfo: Tuple[Type[Exception], Exception, TracebackType],
|
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(path, excinfo)
|
super().__init__(path, excinfo)
|
||||||
self.path = path
|
self.path = path
|
||||||
|
@ -342,9 +342,9 @@ class PytestPluginManager(PluginManager):
|
||||||
self._conftest_plugins: Set[types.ModuleType] = set()
|
self._conftest_plugins: Set[types.ModuleType] = set()
|
||||||
|
|
||||||
# State related to local conftest plugins.
|
# State related to local conftest plugins.
|
||||||
self._dirpath2confmods: Dict[py.path.local, List[types.ModuleType]] = {}
|
self._dirpath2confmods: Dict[Path, List[types.ModuleType]] = {}
|
||||||
self._conftestpath2mod: Dict[Path, types.ModuleType] = {}
|
self._conftestpath2mod: Dict[Path, types.ModuleType] = {}
|
||||||
self._confcutdir: Optional[py.path.local] = None
|
self._confcutdir: Optional[Path] = None
|
||||||
self._noconftest = False
|
self._noconftest = False
|
||||||
self._duplicatepaths: Set[py.path.local] = set()
|
self._duplicatepaths: Set[py.path.local] = set()
|
||||||
|
|
||||||
|
@ -479,9 +479,9 @@ class PytestPluginManager(PluginManager):
|
||||||
All builtin and 3rd party plugins will have been loaded, however, so
|
All builtin and 3rd party plugins will have been loaded, however, so
|
||||||
common options will not confuse our logic here.
|
common options will not confuse our logic here.
|
||||||
"""
|
"""
|
||||||
current = py.path.local()
|
current = Path.cwd()
|
||||||
self._confcutdir = (
|
self._confcutdir = (
|
||||||
current.join(namespace.confcutdir, abs=True)
|
absolutepath(current / namespace.confcutdir)
|
||||||
if namespace.confcutdir
|
if namespace.confcutdir
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
@ -495,7 +495,7 @@ class PytestPluginManager(PluginManager):
|
||||||
i = path.find("::")
|
i = path.find("::")
|
||||||
if i != -1:
|
if i != -1:
|
||||||
path = path[:i]
|
path = path[:i]
|
||||||
anchor = current.join(path, abs=1)
|
anchor = absolutepath(current / path)
|
||||||
if anchor.exists(): # we found some file object
|
if anchor.exists(): # we found some file object
|
||||||
self._try_load_conftest(anchor, namespace.importmode)
|
self._try_load_conftest(anchor, namespace.importmode)
|
||||||
foundanchor = True
|
foundanchor = True
|
||||||
|
@ -503,24 +503,24 @@ class PytestPluginManager(PluginManager):
|
||||||
self._try_load_conftest(current, namespace.importmode)
|
self._try_load_conftest(current, namespace.importmode)
|
||||||
|
|
||||||
def _try_load_conftest(
|
def _try_load_conftest(
|
||||||
self, anchor: py.path.local, importmode: Union[str, ImportMode]
|
self, anchor: Path, importmode: Union[str, ImportMode]
|
||||||
) -> None:
|
) -> None:
|
||||||
self._getconftestmodules(anchor, importmode)
|
self._getconftestmodules(anchor, importmode)
|
||||||
# let's also consider test* subdirs
|
# let's also consider test* subdirs
|
||||||
if anchor.check(dir=1):
|
if anchor.is_dir():
|
||||||
for x in anchor.listdir("test*"):
|
for x in anchor.glob("test*"):
|
||||||
if x.check(dir=1):
|
if x.is_dir():
|
||||||
self._getconftestmodules(x, importmode)
|
self._getconftestmodules(x, importmode)
|
||||||
|
|
||||||
@lru_cache(maxsize=128)
|
@lru_cache(maxsize=128)
|
||||||
def _getconftestmodules(
|
def _getconftestmodules(
|
||||||
self, path: py.path.local, importmode: Union[str, ImportMode],
|
self, path: Path, importmode: Union[str, ImportMode],
|
||||||
) -> List[types.ModuleType]:
|
) -> List[types.ModuleType]:
|
||||||
if self._noconftest:
|
if self._noconftest:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
if path.isfile():
|
if path.is_file():
|
||||||
directory = path.dirpath()
|
directory = path.parent
|
||||||
else:
|
else:
|
||||||
directory = path
|
directory = path
|
||||||
|
|
||||||
|
@ -528,18 +528,18 @@ class PytestPluginManager(PluginManager):
|
||||||
# and allow users to opt into looking into the rootdir parent
|
# and allow users to opt into looking into the rootdir parent
|
||||||
# directories instead of requiring to specify confcutdir.
|
# directories instead of requiring to specify confcutdir.
|
||||||
clist = []
|
clist = []
|
||||||
for parent in directory.parts():
|
for parent in reversed((directory, *directory.parents)):
|
||||||
if self._confcutdir and self._confcutdir.relto(parent):
|
if self._confcutdir and parent in self._confcutdir.parents:
|
||||||
continue
|
continue
|
||||||
conftestpath = parent.join("conftest.py")
|
conftestpath = parent / "conftest.py"
|
||||||
if conftestpath.isfile():
|
if conftestpath.is_file():
|
||||||
mod = self._importconftest(conftestpath, importmode)
|
mod = self._importconftest(conftestpath, importmode)
|
||||||
clist.append(mod)
|
clist.append(mod)
|
||||||
self._dirpath2confmods[directory] = clist
|
self._dirpath2confmods[directory] = clist
|
||||||
return clist
|
return clist
|
||||||
|
|
||||||
def _rget_with_confmod(
|
def _rget_with_confmod(
|
||||||
self, name: str, path: py.path.local, importmode: Union[str, ImportMode],
|
self, name: str, path: Path, importmode: Union[str, ImportMode],
|
||||||
) -> Tuple[types.ModuleType, Any]:
|
) -> Tuple[types.ModuleType, Any]:
|
||||||
modules = self._getconftestmodules(path, importmode)
|
modules = self._getconftestmodules(path, importmode)
|
||||||
for mod in reversed(modules):
|
for mod in reversed(modules):
|
||||||
|
@ -550,21 +550,21 @@ class PytestPluginManager(PluginManager):
|
||||||
raise KeyError(name)
|
raise KeyError(name)
|
||||||
|
|
||||||
def _importconftest(
|
def _importconftest(
|
||||||
self, conftestpath: py.path.local, importmode: Union[str, ImportMode],
|
self, conftestpath: Path, importmode: Union[str, ImportMode],
|
||||||
) -> types.ModuleType:
|
) -> types.ModuleType:
|
||||||
# Use a resolved Path object as key to avoid loading the same conftest
|
# Use a resolved Path object as key to avoid loading the same conftest
|
||||||
# twice with build systems that create build directories containing
|
# twice with build systems that create build directories containing
|
||||||
# symlinks to actual files.
|
# symlinks to actual files.
|
||||||
# Using Path().resolve() is better than py.path.realpath because
|
# Using Path().resolve() is better than py.path.realpath because
|
||||||
# it resolves to the correct path/drive in case-insensitive file systems (#5792)
|
# it resolves to the correct path/drive in case-insensitive file systems (#5792)
|
||||||
key = Path(str(conftestpath)).resolve()
|
key = conftestpath.resolve()
|
||||||
|
|
||||||
with contextlib.suppress(KeyError):
|
with contextlib.suppress(KeyError):
|
||||||
return self._conftestpath2mod[key]
|
return self._conftestpath2mod[key]
|
||||||
|
|
||||||
pkgpath = conftestpath.pypkgpath()
|
pkgpath = resolve_package_path(conftestpath)
|
||||||
if pkgpath is None:
|
if pkgpath is None:
|
||||||
_ensure_removed_sysmodule(conftestpath.purebasename)
|
_ensure_removed_sysmodule(conftestpath.stem)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
mod = import_path(conftestpath, mode=importmode)
|
mod = import_path(conftestpath, mode=importmode)
|
||||||
|
@ -577,10 +577,10 @@ class PytestPluginManager(PluginManager):
|
||||||
|
|
||||||
self._conftest_plugins.add(mod)
|
self._conftest_plugins.add(mod)
|
||||||
self._conftestpath2mod[key] = mod
|
self._conftestpath2mod[key] = mod
|
||||||
dirpath = conftestpath.dirpath()
|
dirpath = conftestpath.parent
|
||||||
if dirpath in self._dirpath2confmods:
|
if dirpath in self._dirpath2confmods:
|
||||||
for path, mods in self._dirpath2confmods.items():
|
for path, mods in self._dirpath2confmods.items():
|
||||||
if path and path.relto(dirpath) or path == dirpath:
|
if path and dirpath in path.parents or path == dirpath:
|
||||||
assert mod not in mods
|
assert mod not in mods
|
||||||
mods.append(mod)
|
mods.append(mod)
|
||||||
self.trace(f"loading conftestmodule {mod!r}")
|
self.trace(f"loading conftestmodule {mod!r}")
|
||||||
|
@ -588,7 +588,7 @@ class PytestPluginManager(PluginManager):
|
||||||
return mod
|
return mod
|
||||||
|
|
||||||
def _check_non_top_pytest_plugins(
|
def _check_non_top_pytest_plugins(
|
||||||
self, mod: types.ModuleType, conftestpath: py.path.local,
|
self, mod: types.ModuleType, conftestpath: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
if (
|
if (
|
||||||
hasattr(mod, "pytest_plugins")
|
hasattr(mod, "pytest_plugins")
|
||||||
|
@ -1412,21 +1412,23 @@ class Config:
|
||||||
assert type in [None, "string"]
|
assert type in [None, "string"]
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def _getconftest_pathlist(
|
def _getconftest_pathlist(self, name: str, path: Path) -> Optional[List[Path]]:
|
||||||
self, name: str, path: py.path.local
|
|
||||||
) -> Optional[List[py.path.local]]:
|
|
||||||
try:
|
try:
|
||||||
mod, relroots = self.pluginmanager._rget_with_confmod(
|
mod, relroots = self.pluginmanager._rget_with_confmod(
|
||||||
name, path, self.getoption("importmode")
|
name, path, self.getoption("importmode")
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None
|
||||||
modpath = py.path.local(mod.__file__).dirpath()
|
modpath = Path(mod.__file__).parent
|
||||||
values: List[py.path.local] = []
|
values: List[Path] = []
|
||||||
for relroot in relroots:
|
for relroot in relroots:
|
||||||
if not isinstance(relroot, py.path.local):
|
if isinstance(relroot, Path):
|
||||||
|
pass
|
||||||
|
elif isinstance(relroot, py.path.local):
|
||||||
|
relroot = Path(relroot)
|
||||||
|
else:
|
||||||
relroot = relroot.replace("/", os.sep)
|
relroot = relroot.replace("/", os.sep)
|
||||||
relroot = modpath.join(relroot, abs=True)
|
relroot = absolutepath(modpath / relroot)
|
||||||
values.append(relroot)
|
values.append(relroot)
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import traceback
|
||||||
import types
|
import types
|
||||||
import warnings
|
import warnings
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
@ -525,7 +526,7 @@ class DoctestModule(pytest.Module):
|
||||||
|
|
||||||
if self.fspath.basename == "conftest.py":
|
if self.fspath.basename == "conftest.py":
|
||||||
module = self.config.pluginmanager._importconftest(
|
module = self.config.pluginmanager._importconftest(
|
||||||
self.fspath, self.config.getoption("importmode")
|
Path(self.fspath), self.config.getoption("importmode")
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -371,22 +371,23 @@ def _in_venv(path: py.path.local) -> bool:
|
||||||
|
|
||||||
|
|
||||||
def pytest_ignore_collect(path: py.path.local, config: Config) -> Optional[bool]:
|
def pytest_ignore_collect(path: py.path.local, config: Config) -> Optional[bool]:
|
||||||
ignore_paths = config._getconftest_pathlist("collect_ignore", path=path.dirpath())
|
path_ = Path(path)
|
||||||
|
ignore_paths = config._getconftest_pathlist("collect_ignore", path=path_.parent)
|
||||||
ignore_paths = ignore_paths or []
|
ignore_paths = ignore_paths or []
|
||||||
excludeopt = config.getoption("ignore")
|
excludeopt = config.getoption("ignore")
|
||||||
if excludeopt:
|
if excludeopt:
|
||||||
ignore_paths.extend([py.path.local(x) for x in excludeopt])
|
ignore_paths.extend(absolutepath(x) for x in excludeopt)
|
||||||
|
|
||||||
if py.path.local(path) in ignore_paths:
|
if path_ in ignore_paths:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
ignore_globs = config._getconftest_pathlist(
|
ignore_globs = config._getconftest_pathlist(
|
||||||
"collect_ignore_glob", path=path.dirpath()
|
"collect_ignore_glob", path=path_.parent
|
||||||
)
|
)
|
||||||
ignore_globs = ignore_globs or []
|
ignore_globs = ignore_globs or []
|
||||||
excludeglobopt = config.getoption("ignore_glob")
|
excludeglobopt = config.getoption("ignore_glob")
|
||||||
if excludeglobopt:
|
if excludeglobopt:
|
||||||
ignore_globs.extend([py.path.local(x) for x in excludeglobopt])
|
ignore_globs.extend(absolutepath(x) for x in excludeglobopt)
|
||||||
|
|
||||||
if any(fnmatch.fnmatch(str(path), str(glob)) for glob in ignore_globs):
|
if any(fnmatch.fnmatch(str(path), str(glob)) for glob in ignore_globs):
|
||||||
return True
|
return True
|
||||||
|
@ -512,12 +513,12 @@ class Session(nodes.FSCollector):
|
||||||
def isinitpath(self, path: py.path.local) -> bool:
|
def isinitpath(self, path: py.path.local) -> bool:
|
||||||
return path in self._initialpaths
|
return path in self._initialpaths
|
||||||
|
|
||||||
def gethookproxy(self, fspath: py.path.local):
|
def gethookproxy(self, fspath: "os.PathLike[str]"):
|
||||||
# Check if we have the common case of running
|
# Check if we have the common case of running
|
||||||
# hooks with all conftest.py files.
|
# hooks with all conftest.py files.
|
||||||
pm = self.config.pluginmanager
|
pm = self.config.pluginmanager
|
||||||
my_conftestmodules = pm._getconftestmodules(
|
my_conftestmodules = pm._getconftestmodules(
|
||||||
fspath, self.config.getoption("importmode")
|
Path(fspath), self.config.getoption("importmode")
|
||||||
)
|
)
|
||||||
remove_mods = pm._conftest_plugins.difference(my_conftestmodules)
|
remove_mods = pm._conftest_plugins.difference(my_conftestmodules)
|
||||||
if remove_mods:
|
if remove_mods:
|
||||||
|
@ -668,8 +669,9 @@ class Session(nodes.FSCollector):
|
||||||
# No point in finding packages when collecting doctests.
|
# No point in finding packages when collecting doctests.
|
||||||
if not self.config.getoption("doctestmodules", False):
|
if not self.config.getoption("doctestmodules", False):
|
||||||
pm = self.config.pluginmanager
|
pm = self.config.pluginmanager
|
||||||
|
confcutdir = py.path.local(pm._confcutdir) if pm._confcutdir else None
|
||||||
for parent in reversed(argpath.parts()):
|
for parent in reversed(argpath.parts()):
|
||||||
if pm._confcutdir and pm._confcutdir.relto(parent):
|
if confcutdir and confcutdir.relto(parent):
|
||||||
break
|
break
|
||||||
|
|
||||||
if parent.isdir():
|
if parent.isdir():
|
||||||
|
|
|
@ -520,7 +520,7 @@ class FSCollector(Collector):
|
||||||
"""The public constructor."""
|
"""The public constructor."""
|
||||||
return super().from_parent(parent=parent, fspath=fspath, **kw)
|
return super().from_parent(parent=parent, fspath=fspath, **kw)
|
||||||
|
|
||||||
def gethookproxy(self, fspath: py.path.local):
|
def gethookproxy(self, fspath: "os.PathLike[str]"):
|
||||||
warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
|
warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
|
||||||
return self.session.gethookproxy(fspath)
|
return self.session.gethookproxy(fspath)
|
||||||
|
|
||||||
|
|
|
@ -653,7 +653,7 @@ class Package(Module):
|
||||||
func = partial(_call_with_optional_argument, teardown_module, self.obj)
|
func = partial(_call_with_optional_argument, teardown_module, self.obj)
|
||||||
self.addfinalizer(func)
|
self.addfinalizer(func)
|
||||||
|
|
||||||
def gethookproxy(self, fspath: py.path.local):
|
def gethookproxy(self, fspath: "os.PathLike[str]"):
|
||||||
warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
|
warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
|
||||||
return self.session.gethookproxy(fspath)
|
return self.session.gethookproxy(fspath)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from _pytest.compat import getfuncargnames
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.fixtures import FixtureRequest
|
from _pytest.fixtures import FixtureRequest
|
||||||
from _pytest.pytester import get_public_names
|
from _pytest.pytester import get_public_names
|
||||||
|
from _pytest.pytester import Pytester
|
||||||
from _pytest.pytester import Testdir
|
from _pytest.pytester import Testdir
|
||||||
|
|
||||||
|
|
||||||
|
@ -1961,8 +1962,10 @@ class TestAutouseManagement:
|
||||||
reprec = testdir.inline_run("-v", "-s")
|
reprec = testdir.inline_run("-v", "-s")
|
||||||
reprec.assertoutcome(passed=4)
|
reprec.assertoutcome(passed=4)
|
||||||
|
|
||||||
def test_class_function_parametrization_finalization(self, testdir):
|
def test_class_function_parametrization_finalization(
|
||||||
p = testdir.makeconftest(
|
self, pytester: Pytester
|
||||||
|
) -> None:
|
||||||
|
p = pytester.makeconftest(
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
import pprint
|
import pprint
|
||||||
|
@ -1984,7 +1987,7 @@ class TestAutouseManagement:
|
||||||
request.addfinalizer(fin)
|
request.addfinalizer(fin)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
testdir.makepyfile(
|
pytester.makepyfile(
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -1996,8 +1999,7 @@ class TestAutouseManagement:
|
||||||
pass
|
pass
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
confcut = f"--confcutdir={testdir.tmpdir}"
|
reprec = pytester.inline_run("-v", "-s", "--confcutdir", pytester.path)
|
||||||
reprec = testdir.inline_run("-v", "-s", confcut)
|
|
||||||
reprec.assertoutcome(passed=8)
|
reprec.assertoutcome(passed=8)
|
||||||
config = reprec.getcalls("pytest_unconfigure")[0].config
|
config = reprec.getcalls("pytest_unconfigure")[0].config
|
||||||
values = config.pluginmanager._getconftestmodules(p, importmode="prepend")[
|
values = config.pluginmanager._getconftestmodules(p, importmode="prepend")[
|
||||||
|
|
|
@ -364,7 +364,9 @@ class TestCustomConftests:
|
||||||
def test_collectignore_exclude_on_option(self, pytester: Pytester) -> None:
|
def test_collectignore_exclude_on_option(self, pytester: Pytester) -> None:
|
||||||
pytester.makeconftest(
|
pytester.makeconftest(
|
||||||
"""
|
"""
|
||||||
collect_ignore = ['hello', 'test_world.py']
|
import py
|
||||||
|
from pathlib import Path
|
||||||
|
collect_ignore = [py.path.local('hello'), 'test_world.py', Path('bye')]
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption("--XX", action="store_true", default=False)
|
parser.addoption("--XX", action="store_true", default=False)
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
|
|
|
@ -574,16 +574,16 @@ class TestConfigAPI:
|
||||||
config.getvalue("x")
|
config.getvalue("x")
|
||||||
assert config.getoption("x", 1) == 1
|
assert config.getoption("x", 1) == 1
|
||||||
|
|
||||||
def test_getconftest_pathlist(self, pytester: Pytester, tmpdir) -> None:
|
def test_getconftest_pathlist(self, pytester: Pytester, tmp_path: Path) -> None:
|
||||||
somepath = tmpdir.join("x", "y", "z")
|
somepath = tmp_path.joinpath("x", "y", "z")
|
||||||
p = tmpdir.join("conftest.py")
|
p = tmp_path.joinpath("conftest.py")
|
||||||
p.write("pathlist = ['.', %r]" % str(somepath))
|
p.write_text(f"pathlist = ['.', {str(somepath)!r}]")
|
||||||
config = pytester.parseconfigure(p)
|
config = pytester.parseconfigure(p)
|
||||||
assert config._getconftest_pathlist("notexist", path=tmpdir) is None
|
assert config._getconftest_pathlist("notexist", path=tmp_path) is None
|
||||||
pl = config._getconftest_pathlist("pathlist", path=tmpdir) or []
|
pl = config._getconftest_pathlist("pathlist", path=tmp_path) or []
|
||||||
print(pl)
|
print(pl)
|
||||||
assert len(pl) == 2
|
assert len(pl) == 2
|
||||||
assert pl[0] == tmpdir
|
assert pl[0] == tmp_path
|
||||||
assert pl[1] == somepath
|
assert pl[1] == somepath
|
||||||
|
|
||||||
@pytest.mark.parametrize("maybe_type", ["not passed", "None", '"string"'])
|
@pytest.mark.parametrize("maybe_type", ["not passed", "None", '"string"'])
|
||||||
|
@ -1935,10 +1935,10 @@ class TestPytestPluginsVariable:
|
||||||
assert msg not in res.stdout.str()
|
assert msg not in res.stdout.str()
|
||||||
|
|
||||||
|
|
||||||
def test_conftest_import_error_repr(tmpdir: py.path.local) -> None:
|
def test_conftest_import_error_repr(tmp_path: Path) -> None:
|
||||||
"""`ConftestImportFailure` should use a short error message and readable
|
"""`ConftestImportFailure` should use a short error message and readable
|
||||||
path to the failed conftest.py file."""
|
path to the failed conftest.py file."""
|
||||||
path = tmpdir.join("foo/conftest.py")
|
path = tmp_path.joinpath("foo/conftest.py")
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ConftestImportFailure,
|
ConftestImportFailure,
|
||||||
match=re.escape(f"RuntimeError: some error (from {path})"),
|
match=re.escape(f"RuntimeError: some error (from {path})"),
|
||||||
|
|
|
@ -4,6 +4,7 @@ import textwrap
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ from _pytest.config import PytestPluginManager
|
||||||
from _pytest.monkeypatch import MonkeyPatch
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
from _pytest.pathlib import symlink_or_skip
|
from _pytest.pathlib import symlink_or_skip
|
||||||
from _pytest.pytester import Pytester
|
from _pytest.pytester import Pytester
|
||||||
from _pytest.pytester import Testdir
|
from _pytest.tmpdir import TempPathFactory
|
||||||
|
|
||||||
|
|
||||||
def ConftestWithSetinitial(path) -> PytestPluginManager:
|
def ConftestWithSetinitial(path) -> PytestPluginManager:
|
||||||
|
@ -25,12 +26,12 @@ def ConftestWithSetinitial(path) -> PytestPluginManager:
|
||||||
|
|
||||||
|
|
||||||
def conftest_setinitial(
|
def conftest_setinitial(
|
||||||
conftest: PytestPluginManager, args, confcutdir: Optional[py.path.local] = None
|
conftest: PytestPluginManager, args, confcutdir: Optional["os.PathLike[str]"] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
class Namespace:
|
class Namespace:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.file_or_dir = args
|
self.file_or_dir = args
|
||||||
self.confcutdir = str(confcutdir)
|
self.confcutdir = os.fspath(confcutdir) if confcutdir is not None else None
|
||||||
self.noconftest = False
|
self.noconftest = False
|
||||||
self.pyargs = False
|
self.pyargs = False
|
||||||
self.importmode = "prepend"
|
self.importmode = "prepend"
|
||||||
|
@ -42,54 +43,58 @@ def conftest_setinitial(
|
||||||
@pytest.mark.usefixtures("_sys_snapshot")
|
@pytest.mark.usefixtures("_sys_snapshot")
|
||||||
class TestConftestValueAccessGlobal:
|
class TestConftestValueAccessGlobal:
|
||||||
@pytest.fixture(scope="module", params=["global", "inpackage"])
|
@pytest.fixture(scope="module", params=["global", "inpackage"])
|
||||||
def basedir(self, request, tmpdir_factory):
|
def basedir(
|
||||||
tmpdir = tmpdir_factory.mktemp("basedir", numbered=True)
|
self, request, tmp_path_factory: TempPathFactory
|
||||||
tmpdir.ensure("adir/conftest.py").write("a=1 ; Directory = 3")
|
) -> Generator[Path, None, None]:
|
||||||
tmpdir.ensure("adir/b/conftest.py").write("b=2 ; a = 1.5")
|
tmpdir = tmp_path_factory.mktemp("basedir", numbered=True)
|
||||||
|
tmpdir.joinpath("adir/b").mkdir(parents=True)
|
||||||
|
tmpdir.joinpath("adir/conftest.py").write_text("a=1 ; Directory = 3")
|
||||||
|
tmpdir.joinpath("adir/b/conftest.py").write_text("b=2 ; a = 1.5")
|
||||||
if request.param == "inpackage":
|
if request.param == "inpackage":
|
||||||
tmpdir.ensure("adir/__init__.py")
|
tmpdir.joinpath("adir/__init__.py").touch()
|
||||||
tmpdir.ensure("adir/b/__init__.py")
|
tmpdir.joinpath("adir/b/__init__.py").touch()
|
||||||
|
|
||||||
yield tmpdir
|
yield tmpdir
|
||||||
|
|
||||||
def test_basic_init(self, basedir):
|
def test_basic_init(self, basedir: Path) -> None:
|
||||||
conftest = PytestPluginManager()
|
conftest = PytestPluginManager()
|
||||||
p = basedir.join("adir")
|
p = basedir / "adir"
|
||||||
assert conftest._rget_with_confmod("a", p, importmode="prepend")[1] == 1
|
assert conftest._rget_with_confmod("a", p, importmode="prepend")[1] == 1
|
||||||
|
|
||||||
def test_immediate_initialiation_and_incremental_are_the_same(self, basedir):
|
def test_immediate_initialiation_and_incremental_are_the_same(
|
||||||
|
self, basedir: Path
|
||||||
|
) -> None:
|
||||||
conftest = PytestPluginManager()
|
conftest = PytestPluginManager()
|
||||||
assert not len(conftest._dirpath2confmods)
|
assert not len(conftest._dirpath2confmods)
|
||||||
conftest._getconftestmodules(basedir, importmode="prepend")
|
conftest._getconftestmodules(basedir, importmode="prepend")
|
||||||
snap1 = len(conftest._dirpath2confmods)
|
snap1 = len(conftest._dirpath2confmods)
|
||||||
assert snap1 == 1
|
assert snap1 == 1
|
||||||
conftest._getconftestmodules(basedir.join("adir"), importmode="prepend")
|
conftest._getconftestmodules(basedir / "adir", importmode="prepend")
|
||||||
assert len(conftest._dirpath2confmods) == snap1 + 1
|
assert len(conftest._dirpath2confmods) == snap1 + 1
|
||||||
conftest._getconftestmodules(basedir.join("b"), importmode="prepend")
|
conftest._getconftestmodules(basedir / "b", importmode="prepend")
|
||||||
assert len(conftest._dirpath2confmods) == snap1 + 2
|
assert len(conftest._dirpath2confmods) == snap1 + 2
|
||||||
|
|
||||||
def test_value_access_not_existing(self, basedir):
|
def test_value_access_not_existing(self, basedir: Path) -> None:
|
||||||
conftest = ConftestWithSetinitial(basedir)
|
conftest = ConftestWithSetinitial(basedir)
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
conftest._rget_with_confmod("a", basedir, importmode="prepend")
|
conftest._rget_with_confmod("a", basedir, importmode="prepend")
|
||||||
|
|
||||||
def test_value_access_by_path(self, basedir):
|
def test_value_access_by_path(self, basedir: Path) -> None:
|
||||||
conftest = ConftestWithSetinitial(basedir)
|
conftest = ConftestWithSetinitial(basedir)
|
||||||
adir = basedir.join("adir")
|
adir = basedir / "adir"
|
||||||
assert conftest._rget_with_confmod("a", adir, importmode="prepend")[1] == 1
|
assert conftest._rget_with_confmod("a", adir, importmode="prepend")[1] == 1
|
||||||
assert (
|
assert (
|
||||||
conftest._rget_with_confmod("a", adir.join("b"), importmode="prepend")[1]
|
conftest._rget_with_confmod("a", adir / "b", importmode="prepend")[1] == 1.5
|
||||||
== 1.5
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_value_access_with_confmod(self, basedir):
|
def test_value_access_with_confmod(self, basedir: Path) -> None:
|
||||||
startdir = basedir.join("adir", "b")
|
startdir = basedir / "adir" / "b"
|
||||||
startdir.ensure("xx", dir=True)
|
startdir.joinpath("xx").mkdir()
|
||||||
conftest = ConftestWithSetinitial(startdir)
|
conftest = ConftestWithSetinitial(startdir)
|
||||||
mod, value = conftest._rget_with_confmod("a", startdir, importmode="prepend")
|
mod, value = conftest._rget_with_confmod("a", startdir, importmode="prepend")
|
||||||
assert value == 1.5
|
assert value == 1.5
|
||||||
path = py.path.local(mod.__file__)
|
path = py.path.local(mod.__file__)
|
||||||
assert path.dirpath() == basedir.join("adir", "b")
|
assert path.dirpath() == basedir / "adir" / "b"
|
||||||
assert path.purebasename.startswith("conftest")
|
assert path.purebasename.startswith("conftest")
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,12 +107,12 @@ def test_conftest_in_nonpkg_with_init(tmp_path: Path, _sys_snapshot) -> None:
|
||||||
ConftestWithSetinitial(tmp_path.joinpath("adir-1.0", "b"))
|
ConftestWithSetinitial(tmp_path.joinpath("adir-1.0", "b"))
|
||||||
|
|
||||||
|
|
||||||
def test_doubledash_considered(testdir: Testdir) -> None:
|
def test_doubledash_considered(pytester: Pytester) -> None:
|
||||||
conf = testdir.mkdir("--option")
|
conf = pytester.mkdir("--option")
|
||||||
conf.join("conftest.py").ensure()
|
conf.joinpath("conftest.py").touch()
|
||||||
conftest = PytestPluginManager()
|
conftest = PytestPluginManager()
|
||||||
conftest_setinitial(conftest, [conf.basename, conf.basename])
|
conftest_setinitial(conftest, [conf.name, conf.name])
|
||||||
values = conftest._getconftestmodules(py.path.local(conf), importmode="prepend")
|
values = conftest._getconftestmodules(conf, importmode="prepend")
|
||||||
assert len(values) == 1
|
assert len(values) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,15 +132,18 @@ def test_conftest_global_import(pytester: Pytester) -> None:
|
||||||
pytester.makeconftest("x=3")
|
pytester.makeconftest("x=3")
|
||||||
p = pytester.makepyfile(
|
p = pytester.makepyfile(
|
||||||
"""
|
"""
|
||||||
import py, pytest
|
from pathlib import Path
|
||||||
|
import pytest
|
||||||
from _pytest.config import PytestPluginManager
|
from _pytest.config import PytestPluginManager
|
||||||
conf = PytestPluginManager()
|
conf = PytestPluginManager()
|
||||||
mod = conf._importconftest(py.path.local("conftest.py"), importmode="prepend")
|
mod = conf._importconftest(Path("conftest.py"), importmode="prepend")
|
||||||
assert mod.x == 3
|
assert mod.x == 3
|
||||||
import conftest
|
import conftest
|
||||||
assert conftest is mod, (conftest, mod)
|
assert conftest is mod, (conftest, mod)
|
||||||
subconf = py.path.local().ensure("sub", "conftest.py")
|
sub = Path("sub")
|
||||||
subconf.write("y=4")
|
sub.mkdir()
|
||||||
|
subconf = sub / "conftest.py"
|
||||||
|
subconf.write_text("y=4")
|
||||||
mod2 = conf._importconftest(subconf, importmode="prepend")
|
mod2 = conf._importconftest(subconf, importmode="prepend")
|
||||||
assert mod != mod2
|
assert mod != mod2
|
||||||
assert mod2.y == 4
|
assert mod2.y == 4
|
||||||
|
@ -147,19 +155,19 @@ def test_conftest_global_import(pytester: Pytester) -> None:
|
||||||
assert res.ret == 0
|
assert res.ret == 0
|
||||||
|
|
||||||
|
|
||||||
def test_conftestcutdir(testdir: Testdir) -> None:
|
def test_conftestcutdir(pytester: Pytester) -> None:
|
||||||
conf = testdir.makeconftest("")
|
conf = pytester.makeconftest("")
|
||||||
p = testdir.mkdir("x")
|
p = pytester.mkdir("x")
|
||||||
conftest = PytestPluginManager()
|
conftest = PytestPluginManager()
|
||||||
conftest_setinitial(conftest, [testdir.tmpdir], confcutdir=p)
|
conftest_setinitial(conftest, [pytester.path], confcutdir=p)
|
||||||
values = conftest._getconftestmodules(p, importmode="prepend")
|
values = conftest._getconftestmodules(p, importmode="prepend")
|
||||||
assert len(values) == 0
|
assert len(values) == 0
|
||||||
values = conftest._getconftestmodules(conf.dirpath(), importmode="prepend")
|
values = conftest._getconftestmodules(conf.parent, importmode="prepend")
|
||||||
assert len(values) == 0
|
assert len(values) == 0
|
||||||
assert Path(conf) not in conftest._conftestpath2mod
|
assert Path(conf) not in conftest._conftestpath2mod
|
||||||
# but we can still import a conftest directly
|
# but we can still import a conftest directly
|
||||||
conftest._importconftest(conf, importmode="prepend")
|
conftest._importconftest(conf, importmode="prepend")
|
||||||
values = conftest._getconftestmodules(conf.dirpath(), importmode="prepend")
|
values = conftest._getconftestmodules(conf.parent, importmode="prepend")
|
||||||
assert values[0].__file__.startswith(str(conf))
|
assert values[0].__file__.startswith(str(conf))
|
||||||
# and all sub paths get updated properly
|
# and all sub paths get updated properly
|
||||||
values = conftest._getconftestmodules(p, importmode="prepend")
|
values = conftest._getconftestmodules(p, importmode="prepend")
|
||||||
|
@ -170,10 +178,8 @@ def test_conftestcutdir(testdir: Testdir) -> None:
|
||||||
def test_conftestcutdir_inplace_considered(pytester: Pytester) -> None:
|
def test_conftestcutdir_inplace_considered(pytester: Pytester) -> None:
|
||||||
conf = pytester.makeconftest("")
|
conf = pytester.makeconftest("")
|
||||||
conftest = PytestPluginManager()
|
conftest = PytestPluginManager()
|
||||||
conftest_setinitial(conftest, [conf.parent], confcutdir=py.path.local(conf.parent))
|
conftest_setinitial(conftest, [conf.parent], confcutdir=conf.parent)
|
||||||
values = conftest._getconftestmodules(
|
values = conftest._getconftestmodules(conf.parent, importmode="prepend")
|
||||||
py.path.local(conf.parent), importmode="prepend"
|
|
||||||
)
|
|
||||||
assert len(values) == 1
|
assert len(values) == 1
|
||||||
assert values[0].__file__.startswith(str(conf))
|
assert values[0].__file__.startswith(str(conf))
|
||||||
|
|
||||||
|
@ -184,7 +190,7 @@ def test_setinitial_conftest_subdirs(pytester: Pytester, name: str) -> None:
|
||||||
subconftest = sub.joinpath("conftest.py")
|
subconftest = sub.joinpath("conftest.py")
|
||||||
subconftest.touch()
|
subconftest.touch()
|
||||||
conftest = PytestPluginManager()
|
conftest = PytestPluginManager()
|
||||||
conftest_setinitial(conftest, [sub.parent], confcutdir=py.path.local(pytester.path))
|
conftest_setinitial(conftest, [sub.parent], confcutdir=pytester.path)
|
||||||
key = subconftest.resolve()
|
key = subconftest.resolve()
|
||||||
if name not in ("whatever", ".dotdir"):
|
if name not in ("whatever", ".dotdir"):
|
||||||
assert key in conftest._conftestpath2mod
|
assert key in conftest._conftestpath2mod
|
||||||
|
@ -337,22 +343,19 @@ def test_conftest_existing_junitxml(pytester: Pytester) -> None:
|
||||||
result.stdout.fnmatch_lines(["*--xyz*"])
|
result.stdout.fnmatch_lines(["*--xyz*"])
|
||||||
|
|
||||||
|
|
||||||
def test_conftest_import_order(testdir: Testdir, monkeypatch: MonkeyPatch) -> None:
|
def test_conftest_import_order(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
|
||||||
ct1 = testdir.makeconftest("")
|
ct1 = pytester.makeconftest("")
|
||||||
sub = testdir.mkdir("sub")
|
sub = pytester.mkdir("sub")
|
||||||
ct2 = sub.join("conftest.py")
|
ct2 = sub / "conftest.py"
|
||||||
ct2.write("")
|
ct2.write_text("")
|
||||||
|
|
||||||
def impct(p, importmode):
|
def impct(p, importmode):
|
||||||
return p
|
return p
|
||||||
|
|
||||||
conftest = PytestPluginManager()
|
conftest = PytestPluginManager()
|
||||||
conftest._confcutdir = testdir.tmpdir
|
conftest._confcutdir = pytester.path
|
||||||
monkeypatch.setattr(conftest, "_importconftest", impct)
|
monkeypatch.setattr(conftest, "_importconftest", impct)
|
||||||
mods = cast(
|
mods = cast(List[Path], conftest._getconftestmodules(sub, importmode="prepend"))
|
||||||
List[py.path.local],
|
|
||||||
conftest._getconftestmodules(py.path.local(sub), importmode="prepend"),
|
|
||||||
)
|
|
||||||
expected = [ct1, ct2]
|
expected = [ct1, ct2]
|
||||||
assert mods == expected
|
assert mods == expected
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from _pytest.config import ExitCode
|
||||||
from _pytest.config import PytestPluginManager
|
from _pytest.config import PytestPluginManager
|
||||||
from _pytest.config.exceptions import UsageError
|
from _pytest.config.exceptions import UsageError
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
|
from _pytest.pytester import Pytester
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -16,14 +17,16 @@ def pytestpm() -> PytestPluginManager:
|
||||||
|
|
||||||
|
|
||||||
class TestPytestPluginInteractions:
|
class TestPytestPluginInteractions:
|
||||||
def test_addhooks_conftestplugin(self, testdir, _config_for_test):
|
def test_addhooks_conftestplugin(
|
||||||
testdir.makepyfile(
|
self, pytester: Pytester, _config_for_test
|
||||||
|
) -> None:
|
||||||
|
pytester.makepyfile(
|
||||||
newhooks="""
|
newhooks="""
|
||||||
def pytest_myhook(xyz):
|
def pytest_myhook(xyz):
|
||||||
"new hook"
|
"new hook"
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
conf = testdir.makeconftest(
|
conf = pytester.makeconftest(
|
||||||
"""
|
"""
|
||||||
import newhooks
|
import newhooks
|
||||||
def pytest_addhooks(pluginmanager):
|
def pytest_addhooks(pluginmanager):
|
||||||
|
@ -54,10 +57,10 @@ class TestPytestPluginInteractions:
|
||||||
assert res.ret != 0
|
assert res.ret != 0
|
||||||
res.stderr.fnmatch_lines(["*did not find*sys*"])
|
res.stderr.fnmatch_lines(["*did not find*sys*"])
|
||||||
|
|
||||||
def test_do_option_postinitialize(self, testdir):
|
def test_do_option_postinitialize(self, pytester: Pytester) -> None:
|
||||||
config = testdir.parseconfigure()
|
config = pytester.parseconfigure()
|
||||||
assert not hasattr(config.option, "test123")
|
assert not hasattr(config.option, "test123")
|
||||||
p = testdir.makepyfile(
|
p = pytester.makepyfile(
|
||||||
"""
|
"""
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption('--test123', action="store_true",
|
parser.addoption('--test123', action="store_true",
|
||||||
|
@ -120,20 +123,20 @@ class TestPytestPluginInteractions:
|
||||||
finally:
|
finally:
|
||||||
undo()
|
undo()
|
||||||
|
|
||||||
def test_hook_proxy(self, testdir):
|
def test_hook_proxy(self, pytester: Pytester) -> None:
|
||||||
"""Test the gethookproxy function(#2016)"""
|
"""Test the gethookproxy function(#2016)"""
|
||||||
config = testdir.parseconfig()
|
config = pytester.parseconfig()
|
||||||
session = Session.from_config(config)
|
session = Session.from_config(config)
|
||||||
testdir.makepyfile(**{"tests/conftest.py": "", "tests/subdir/conftest.py": ""})
|
pytester.makepyfile(**{"tests/conftest.py": "", "tests/subdir/conftest.py": ""})
|
||||||
|
|
||||||
conftest1 = testdir.tmpdir.join("tests/conftest.py")
|
conftest1 = pytester.path.joinpath("tests/conftest.py")
|
||||||
conftest2 = testdir.tmpdir.join("tests/subdir/conftest.py")
|
conftest2 = pytester.path.joinpath("tests/subdir/conftest.py")
|
||||||
|
|
||||||
config.pluginmanager._importconftest(conftest1, importmode="prepend")
|
config.pluginmanager._importconftest(conftest1, importmode="prepend")
|
||||||
ihook_a = session.gethookproxy(testdir.tmpdir.join("tests"))
|
ihook_a = session.gethookproxy(pytester.path / "tests")
|
||||||
assert ihook_a is not None
|
assert ihook_a is not None
|
||||||
config.pluginmanager._importconftest(conftest2, importmode="prepend")
|
config.pluginmanager._importconftest(conftest2, importmode="prepend")
|
||||||
ihook_b = session.gethookproxy(testdir.tmpdir.join("tests"))
|
ihook_b = session.gethookproxy(pytester.path / "tests")
|
||||||
assert ihook_a is not ihook_b
|
assert ihook_a is not ihook_b
|
||||||
|
|
||||||
def test_hook_with_addoption(self, testdir):
|
def test_hook_with_addoption(self, testdir):
|
||||||
|
|
Loading…
Reference in New Issue