Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More py.path removal work #8446

Merged
merged 3 commits into from
Mar 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog/7259.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Added :meth:`cache.mkdir() <pytest.Cache.mkdir>`, which is similar to the existing :meth:`cache.makedir() <pytest.Cache.makedir>`,
but returns a :class:`pathlib.Path` instead of a legacy ``py.path.local``.
8 changes: 4 additions & 4 deletions doc/en/example/nonpython/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
import pytest


def pytest_collect_file(parent, path):
if path.ext == ".yaml" and path.basename.startswith("test"):
return YamlFile.from_parent(parent, fspath=path)
def pytest_collect_file(parent, fspath):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seeing this reminds me - adding those parameters is a breaking changes for externals that use those,

i believe it adds errors on some plugins, please see #8361

if fspath.suffix == ".yaml" and fspath.name.startswith("test"):
return YamlFile.from_parent(parent, path=fspath)


class YamlFile(pytest.File):
def collect(self):
# We need a yaml parser, e.g. PyYAML.
import yaml

raw = yaml.safe_load(self.fspath.open())
raw = yaml.safe_load(self.path.open())
for name, spec in sorted(raw.items()):
yield YamlItem.from_parent(self, name=name, spec=spec)

Expand Down
2 changes: 1 addition & 1 deletion doc/en/reference/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,7 @@ pytest treats some global variables in a special manner when defined in a test m
**Tutorial**: :ref:`customizing-test-collection`

Can be declared in *conftest.py files* to exclude test directories or modules.
Needs to be ``list[str]``.
Needs to be a list of paths (``str``, :class:`pathlib.Path` or any :class:`os.PathLike`).

.. code-block:: python

Expand Down
21 changes: 15 additions & 6 deletions src/_pytest/cacheprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ class Cache:
_cachedir = attr.ib(type=Path, repr=False)
_config = attr.ib(type=Config, repr=False)

# sub-directory under cache-dir for directories created by "makedir"
# Sub-directory under cache-dir for directories created by `mkdir()`.
_CACHE_PREFIX_DIRS = "d"

# sub-directory under cache-dir for values created by "set"
# Sub-directory under cache-dir for values created by `set()`.
_CACHE_PREFIX_VALUES = "v"

def __init__(
Expand Down Expand Up @@ -121,13 +121,15 @@ def warn(self, fmt: str, *, _ispytest: bool = False, **args: object) -> None:
stacklevel=3,
)

def makedir(self, name: str) -> LEGACY_PATH:
def mkdir(self, name: str) -> Path:
"""Return a directory path object with the given name.

If the directory does not yet exist, it will be created. You can use
it to manage files to e.g. store/retrieve database dumps across test
sessions.

.. versionadded:: 6.3

:param name:
Must be a string not containing a ``/`` separator.
Make sure the name contains your plugin or application
Expand All @@ -138,7 +140,14 @@ def makedir(self, name: str) -> LEGACY_PATH:
raise ValueError("name is not allowed to contain path separators")
res = self._cachedir.joinpath(self._CACHE_PREFIX_DIRS, path)
res.mkdir(exist_ok=True, parents=True)
return legacy_path(res)
return res

def makedir(self, name: str) -> LEGACY_PATH:
"""Return a directory path object with the given name.

Same as :func:`mkdir`, but returns a legacy py path instance.
"""
return legacy_path(self.mkdir(name))

def _getvaluepath(self, key: str) -> Path:
return self._cachedir.joinpath(self._CACHE_PREFIX_VALUES, Path(key))
Expand Down Expand Up @@ -572,8 +581,8 @@ def cacheshow(config: Config, session: Session) -> int:
contents = sorted(ddir.rglob(glob))
tw.sep("-", "cache directories for %r" % glob)
for p in contents:
# if p.check(dir=1):
# print("%s/" % p.relto(basedir))
# if p.is_dir():
# print("%s/" % p.relative_to(basedir))
if p.is_file():
key = str(p.relative_to(basedir))
tw.line(f"{key} is a file of length {p.stat().st_size:d}")
Expand Down
4 changes: 1 addition & 3 deletions src/_pytest/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1445,9 +1445,7 @@ def _getconftest_pathlist(self, name: str, path: Path) -> Optional[List[Path]]:
modpath = Path(mod.__file__).parent
values: List[Path] = []
for relroot in relroots:
if isinstance(relroot, Path):
pass
elif isinstance(relroot, LEGACY_PATH):
if isinstance(relroot, os.PathLike):
relroot = Path(relroot)
else:
relroot = relroot.replace("/", os.sep)
Expand Down
2 changes: 0 additions & 2 deletions src/_pytest/doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
from _pytest._code.code import ReprFileLocation
from _pytest._code.code import TerminalRepr
from _pytest._io import TerminalWriter
from _pytest.compat import LEGACY_PATH
from _pytest.compat import legacy_path
from _pytest.compat import safe_getattr
from _pytest.config import Config
Expand Down Expand Up @@ -122,7 +121,6 @@ def pytest_unconfigure() -> None:

def pytest_collect_file(
fspath: Path,
path: LEGACY_PATH,
parent: Collector,
) -> Optional[Union["DoctestModule", "DoctestTextfile"]]:
config = parent.config
Expand Down
2 changes: 1 addition & 1 deletion src/_pytest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ class Session(nodes.FSCollector):
def __init__(self, config: Config) -> None:
super().__init__(
path=config.rootpath,
fspath=config.rootdir,
fspath=None,
parent=None,
config=config,
session=self,
Expand Down
2 changes: 1 addition & 1 deletion src/_pytest/pytester.py
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,7 @@ def copy_example(self, name: Optional[str] = None) -> Path:
example_dir = self._request.config.getini("pytester_example_dir")
if example_dir is None:
raise ValueError("pytester_example_dir is unset, can't copy examples")
example_dir = Path(str(self._request.config.rootdir)) / example_dir
example_dir = self._request.config.rootpath / example_dir

for extra_element in self._request.node.iter_markers("pytester_example_path"):
assert extra_element.args
Expand Down
8 changes: 4 additions & 4 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,11 @@ def path_matches_patterns(path: Path, patterns: Iterable[str]) -> bool:
return any(fnmatch_ex(pattern, path) for pattern in patterns)


def pytest_pycollect_makemodule(fspath: Path, path: LEGACY_PATH, parent) -> "Module":
def pytest_pycollect_makemodule(fspath: Path, parent) -> "Module":
if fspath.name == "__init__.py":
pkg: Package = Package.from_parent(parent, fspath=path)
pkg: Package = Package.from_parent(parent, path=fspath)
return pkg
mod: Module = Module.from_parent(parent, fspath=path)
mod: Module = Module.from_parent(parent, path=fspath)
return mod


Expand Down Expand Up @@ -691,7 +691,7 @@ def _collectfile(
assert (
fspath.is_file()
), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(
path, fspath.is_dir(), fspath.exists(), fspath.is_symlink()
fspath, fspath.is_dir(), fspath.exists(), fspath.is_symlink()
)
ihook = self.session.gethookproxy(fspath)
if not self.session.isinitpath(fspath):
Expand Down
6 changes: 3 additions & 3 deletions testing/acceptance_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,9 @@ def runtest(self):
class MyCollector(pytest.File):
def collect(self):
return [MyItem.from_parent(name="xyz", parent=self)]
def pytest_collect_file(path, parent):
if path.basename.startswith("conftest"):
return MyCollector.from_parent(fspath=path, parent=parent)
def pytest_collect_file(fspath, parent):
if fspath.name.startswith("conftest"):
return MyCollector.from_parent(path=fspath, parent=parent)
"""
)
result = pytester.runpytest(c.name + "::" + "xyz")
Expand Down
8 changes: 4 additions & 4 deletions testing/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,13 @@ def dummy_yaml_custom_test(pytester: Pytester):
"""
import pytest
def pytest_collect_file(parent, path):
if path.ext == ".yaml" and path.basename.startswith("test"):
return YamlFile.from_parent(fspath=path, parent=parent)
def pytest_collect_file(parent, fspath):
if fspath.suffix == ".yaml" and fspath.name.startswith("test"):
return YamlFile.from_parent(path=fspath, parent=parent)
class YamlFile(pytest.File):
def collect(self):
yield YamlItem.from_parent(name=self.fspath.basename, parent=self)
yield YamlItem.from_parent(name=self.path.name, parent=self)
class YamlItem(pytest.Item):
def runtest(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
def pytest_ignore_collect(path):
def pytest_ignore_collect(fspath):
return False
4 changes: 2 additions & 2 deletions testing/example_scripts/fixtures/custom_item/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ def collect(self):
yield CustomItem.from_parent(name="foo", parent=self)


def pytest_collect_file(path, parent):
return CustomFile.from_parent(fspath=path, parent=parent)
def pytest_collect_file(fspath, parent):
return CustomFile.from_parent(path=fspath, parent=parent)
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ def collect(self):
return [MyItem.from_parent(name="hello", parent=self)]


def pytest_collect_file(path, parent):
return MyFile.from_parent(fspath=path, parent=parent)
def pytest_collect_file(fspath, parent):
return MyFile.from_parent(path=fspath, parent=parent)


class MyItem(pytest.Item):
Expand Down
12 changes: 6 additions & 6 deletions testing/python/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,9 +778,9 @@ def test_pytest_pycollect_module(self, pytester: Pytester) -> None:
import pytest
class MyModule(pytest.Module):
pass
def pytest_pycollect_makemodule(path, parent):
if path.basename == "test_xyz.py":
return MyModule.from_parent(fspath=path, parent=parent)
def pytest_pycollect_makemodule(fspath, parent):
if fspath.name == "test_xyz.py":
return MyModule.from_parent(path=fspath, parent=parent)
"""
)
pytester.makepyfile("def test_some(): pass")
Expand Down Expand Up @@ -882,9 +882,9 @@ def find_module(self, name, path=None):
return Loader()
sys.meta_path.append(Finder())
def pytest_collect_file(path, parent):
if path.ext == ".narf":
return Module.from_parent(fspath=path, parent=parent)"""
def pytest_collect_file(fspath, parent):
if fspath.suffix == ".narf":
return Module.from_parent(path=fspath, parent=parent)"""
)
pytester.makefile(
".narf",
Expand Down
8 changes: 4 additions & 4 deletions testing/python/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -3208,10 +3208,10 @@ class TestRequestScopeAccess:
pytestmark = pytest.mark.parametrize(
("scope", "ok", "error"),
[
["session", "", "fspath class function module"],
["module", "module fspath", "cls function"],
["class", "module fspath cls", "function"],
["function", "module fspath cls function", ""],
["session", "", "path class function module"],
["module", "module path", "cls function"],
["class", "module path cls", "function"],
["function", "module path cls function", ""],
],
)

Expand Down
14 changes: 7 additions & 7 deletions testing/test_cacheprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@


class TestNewAPI:
def test_config_cache_makedir(self, pytester: Pytester) -> None:
def test_config_cache_mkdir(self, pytester: Pytester) -> None:
pytester.makeini("[pytest]")
config = pytester.parseconfigure()
assert config.cache is not None
with pytest.raises(ValueError):
config.cache.makedir("key/name")
config.cache.mkdir("key/name")

p = config.cache.makedir("name")
assert p.check()
p = config.cache.mkdir("name")
assert p.is_dir()

def test_config_cache_dataerror(self, pytester: Pytester) -> None:
pytester.makeini("[pytest]")
Expand Down Expand Up @@ -217,9 +217,9 @@ def pytest_configure(config):
config.cache.set("my/name", [1,2,3])
config.cache.set("my/hello", "world")
config.cache.set("other/some", {1:2})
dp = config.cache.makedir("mydb")
dp.ensure("hello")
dp.ensure("world")
dp = config.cache.mkdir("mydb")
dp.joinpath("hello").touch()
dp.joinpath("world").touch()
"""
)
result = pytester.runpytest()
Expand Down
Loading