Some py.path.local -> pathlib.Path

This commit is contained in:
Ran Benita 2020-12-14 15:54:59 +02:00
parent cb8142b8ec
commit 2cb34a99cb
10 changed files with 84 additions and 94 deletions

View File

@ -27,8 +27,6 @@ from typing import Tuple
from typing import TYPE_CHECKING
from typing import Union
import py
from _pytest._io.saferepr import saferepr
from _pytest._version import version
from _pytest.assertion import util
@ -37,6 +35,7 @@ from _pytest.assertion.util import ( # noqa: F401
)
from _pytest.config import Config
from _pytest.main import Session
from _pytest.pathlib import absolutepath
from _pytest.pathlib import fnmatch_ex
from _pytest.store import StoreKey
@ -215,7 +214,7 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader)
return True
if self.session is not None:
if self.session.isinitpath(py.path.local(fn)):
if self.session.isinitpath(absolutepath(fn)):
state.trace(f"matched test file (was specified on cmdline): {fn!r}")
return True

View File

@ -1,4 +1,5 @@
import argparse
import os
import sys
import warnings
from gettext import gettext
@ -14,8 +15,6 @@ from typing import Tuple
from typing import TYPE_CHECKING
from typing import Union
import py
import _pytest._io
from _pytest.compat import final
from _pytest.config.exceptions import UsageError
@ -97,14 +96,14 @@ class Parser:
def parse(
self,
args: Sequence[Union[str, py.path.local]],
args: Sequence[Union[str, "os.PathLike[str]"]],
namespace: Optional[argparse.Namespace] = None,
) -> argparse.Namespace:
from _pytest._argcomplete import try_argcomplete
self.optparser = self._getparser()
try_argcomplete(self.optparser)
strargs = [str(x) if isinstance(x, py.path.local) else x for x in args]
strargs = [os.fspath(x) for x in args]
return self.optparser.parse_args(strargs, namespace=namespace)
def _getparser(self) -> "MyOptionParser":
@ -128,7 +127,7 @@ class Parser:
def parse_setoption(
self,
args: Sequence[Union[str, py.path.local]],
args: Sequence[Union[str, "os.PathLike[str]"]],
option: argparse.Namespace,
namespace: Optional[argparse.Namespace] = None,
) -> List[str]:
@ -139,7 +138,7 @@ class Parser:
def parse_known_args(
self,
args: Sequence[Union[str, py.path.local]],
args: Sequence[Union[str, "os.PathLike[str]"]],
namespace: Optional[argparse.Namespace] = None,
) -> argparse.Namespace:
"""Parse and return a namespace object with known arguments at this point."""
@ -147,13 +146,13 @@ class Parser:
def parse_known_and_unknown_args(
self,
args: Sequence[Union[str, py.path.local]],
args: Sequence[Union[str, "os.PathLike[str]"]],
namespace: Optional[argparse.Namespace] = None,
) -> Tuple[argparse.Namespace, List[str]]:
"""Parse and return a namespace object with known arguments, and
the remaining arguments unknown at this point."""
optparser = self._getparser()
strargs = [str(x) if isinstance(x, py.path.local) else x for x in args]
strargs = [os.fspath(x) for x in args]
return optparser.parse_known_args(strargs, namespace=namespace)
def addini(

View File

@ -648,12 +648,13 @@ class FixtureRequest:
if has_params:
frame = inspect.stack()[3]
frameinfo = inspect.getframeinfo(frame[0])
source_path = py.path.local(frameinfo.filename)
source_path = absolutepath(frameinfo.filename)
source_lineno = frameinfo.lineno
rel_source_path = source_path.relto(funcitem.config.rootdir)
if rel_source_path:
source_path_str = rel_source_path
else:
try:
source_path_str = str(
source_path.relative_to(funcitem.config.rootpath)
)
except ValueError:
source_path_str = str(source_path)
msg = (
"The requested fixture has no parameter defined for test:\n"
@ -876,7 +877,7 @@ class FixtureLookupError(LookupError):
class FixtureLookupErrorRepr(TerminalRepr):
def __init__(
self,
filename: Union[str, py.path.local],
filename: Union[str, "os.PathLike[str]"],
firstlineno: int,
tblines: Sequence[str],
errorstring: str,
@ -903,7 +904,7 @@ class FixtureLookupErrorRepr(TerminalRepr):
f"{FormattedExcinfo.flow_marker} {line.strip()}", red=True,
)
tw.line()
tw.line("%s:%d" % (self.filename, self.firstlineno + 1))
tw.line("%s:%d" % (os.fspath(self.filename), self.firstlineno + 1))
def fail_fixturefunc(fixturefunc, msg: str) -> "NoReturn":

View File

@ -467,7 +467,7 @@ class Session(nodes.FSCollector):
self.shouldfail: Union[bool, str] = False
self.trace = config.trace.root.get("collection")
self.startdir = config.invocation_dir
self._initialpaths: FrozenSet[py.path.local] = frozenset()
self._initialpaths: FrozenSet[Path] = frozenset()
self._bestrelpathcache: Dict[Path, str] = _bestrelpath_cache(config.rootpath)
@ -510,8 +510,8 @@ class Session(nodes.FSCollector):
pytest_collectreport = pytest_runtest_logreport
def isinitpath(self, path: py.path.local) -> bool:
return path in self._initialpaths
def isinitpath(self, path: Union[str, "os.PathLike[str]"]) -> bool:
return Path(path) in self._initialpaths
def gethookproxy(self, fspath: "os.PathLike[str]"):
# Check if we have the common case of running
@ -601,14 +601,14 @@ class Session(nodes.FSCollector):
self.trace.root.indent += 1
self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = []
self._initial_parts: List[Tuple[py.path.local, List[str]]] = []
self._initial_parts: List[Tuple[Path, List[str]]] = []
self.items: List[nodes.Item] = []
hook = self.config.hook
items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items
try:
initialpaths: List[py.path.local] = []
initialpaths: List[Path] = []
for arg in args:
fspath, parts = resolve_collection_argument(
self.config.invocation_params.dir,
@ -669,13 +669,13 @@ class Session(nodes.FSCollector):
# No point in finding packages when collecting doctests.
if not self.config.getoption("doctestmodules", False):
pm = self.config.pluginmanager
confcutdir = py.path.local(pm._confcutdir) if pm._confcutdir else None
for parent in reversed(argpath.parts()):
if confcutdir and confcutdir.relto(parent):
confcutdir = pm._confcutdir
for parent in (argpath, *argpath.parents):
if confcutdir and parent in confcutdir.parents:
break
if parent.isdir():
pkginit = parent.join("__init__.py")
if parent.is_dir():
pkginit = py.path.local(parent / "__init__.py")
if pkginit.isfile() and pkginit not in node_cache1:
col = self._collectfile(pkginit, handle_dupes=False)
if col:
@ -685,7 +685,7 @@ class Session(nodes.FSCollector):
# If it's a directory argument, recurse and look for any Subpackages.
# Let the Package collector deal with subnodes, don't collect here.
if argpath.check(dir=1):
if argpath.is_dir():
assert not names, "invalid arg {!r}".format((argpath, names))
seen_dirs: Set[py.path.local] = set()
@ -717,15 +717,16 @@ class Session(nodes.FSCollector):
node_cache2[key] = x
yield x
else:
assert argpath.check(file=1)
assert argpath.is_file()
if argpath in node_cache1:
col = node_cache1[argpath]
argpath_ = py.path.local(argpath)
if argpath_ in node_cache1:
col = node_cache1[argpath_]
else:
collect_root = pkg_roots.get(argpath.dirname, self)
col = collect_root._collectfile(argpath, handle_dupes=False)
collect_root = pkg_roots.get(argpath_.dirname, self)
col = collect_root._collectfile(argpath_, handle_dupes=False)
if col:
node_cache1[argpath] = col
node_cache1[argpath_] = col
matching = []
work: List[
@ -782,9 +783,7 @@ class Session(nodes.FSCollector):
# first yielded item will be the __init__ Module itself, so
# just use that. If this special case isn't taken, then all the
# files in the package will be yielded.
if argpath.basename == "__init__.py" and isinstance(
matching[0], Package
):
if argpath.name == "__init__.py" and isinstance(matching[0], Package):
try:
yield next(iter(matching[0].collect()))
except StopIteration:
@ -833,7 +832,7 @@ def search_pypath(module_name: str) -> str:
def resolve_collection_argument(
invocation_path: Path, arg: str, *, as_pypath: bool = False
) -> Tuple[py.path.local, List[str]]:
) -> Tuple[Path, List[str]]:
"""Parse path arguments optionally containing selection parts and return (fspath, names).
Command-line arguments can point to files and/or directories, and optionally contain
@ -875,4 +874,4 @@ def resolve_collection_argument(
else "directory argument cannot contain :: selection parts: {arg}"
)
raise UsageError(msg.format(arg=arg))
return py.path.local(str(fspath)), parts
return fspath, parts

View File

@ -4,7 +4,6 @@ import re
import sys
import warnings
from contextlib import contextmanager
from pathlib import Path
from typing import Any
from typing import Generator
from typing import List
@ -325,20 +324,14 @@ class MonkeyPatch:
invalidate_caches()
def chdir(self, path) -> None:
def chdir(self, path: Union[str, "os.PathLike[str]"]) -> None:
"""Change the current working directory to the specified path.
Path can be a string or a py.path.local object.
Path can be a string or a path object.
"""
if self._cwd is None:
self._cwd = os.getcwd()
if hasattr(path, "chdir"):
path.chdir()
elif isinstance(path, Path):
# Modern python uses the fspath protocol here LEGACY
os.chdir(str(path))
else:
os.chdir(path)
os.chdir(path)
def undo(self) -> None:
"""Undo previous changes.

View File

@ -480,10 +480,14 @@ class Collector(Node):
excinfo.traceback = ntraceback.filter()
def _check_initialpaths_for_relpath(session, fspath):
def _check_initialpaths_for_relpath(
session: "Session", fspath: py.path.local
) -> Optional[str]:
for initial_path in session._initialpaths:
if fspath.common(initial_path) == initial_path:
return fspath.relto(initial_path)
initial_path_ = py.path.local(initial_path)
if fspath.common(initial_path_) == initial_path_:
return fspath.relto(initial_path_)
return None
class FSCollector(Collector):

View File

@ -30,8 +30,6 @@ from typing import Set
from typing import TypeVar
from typing import Union
import py
from _pytest.compat import assert_never
from _pytest.outcomes import skip
from _pytest.warning_types import PytestWarning
@ -456,7 +454,7 @@ class ImportPathMismatchError(ImportError):
def import_path(
p: Union[str, py.path.local, Path],
p: Union[str, "os.PathLike[str]"],
*,
mode: Union[str, ImportMode] = ImportMode.prepend,
) -> ModuleType:
@ -482,7 +480,7 @@ def import_path(
"""
mode = ImportMode(mode)
path = Path(str(p))
path = Path(p)
if not path.exists():
raise ImportError(path)

View File

@ -17,8 +17,6 @@ from typing import Mapping
from typing import Optional
from typing import Set
import py
import _pytest._code
import pytest
from _pytest.assertion import util
@ -1311,7 +1309,7 @@ class TestEarlyRewriteBailout:
import importlib.machinery
self.find_spec_calls: List[str] = []
self.initial_paths: Set[py.path.local] = set()
self.initial_paths: Set[Path] = set()
class StubSession:
_initialpaths = self.initial_paths
@ -1346,7 +1344,7 @@ class TestEarlyRewriteBailout:
pytester.makepyfile(test_foo="def test_foo(): pass")
pytester.makepyfile(bar="def bar(): pass")
foobar_path = pytester.makepyfile(foobar="def foobar(): pass")
self.initial_paths.add(py.path.local(foobar_path))
self.initial_paths.add(foobar_path)
# conftest files should always be rewritten
assert hook.find_spec("conftest") is not None

View File

@ -4,13 +4,12 @@ import re
from pathlib import Path
from typing import Optional
import py.path
import pytest
from _pytest.config import ExitCode
from _pytest.config import UsageError
from _pytest.main import resolve_collection_argument
from _pytest.main import validate_basetemp
from _pytest.pytester import Pytester
from _pytest.pytester import Testdir
@ -109,40 +108,37 @@ def test_validate_basetemp_integration(testdir):
class TestResolveCollectionArgument:
@pytest.fixture
def invocation_dir(self, testdir: Testdir) -> py.path.local:
testdir.syspathinsert(str(testdir.tmpdir / "src"))
testdir.chdir()
def invocation_path(self, pytester: Pytester) -> Path:
pytester.syspathinsert(pytester.path / "src")
pytester.chdir()
pkg = testdir.tmpdir.join("src/pkg").ensure_dir()
pkg.join("__init__.py").ensure()
pkg.join("test.py").ensure()
return testdir.tmpdir
pkg = pytester.path.joinpath("src/pkg")
pkg.mkdir(parents=True)
pkg.joinpath("__init__.py").touch()
pkg.joinpath("test.py").touch()
return pytester.path
@pytest.fixture
def invocation_path(self, invocation_dir: py.path.local) -> Path:
return Path(str(invocation_dir))
def test_file(self, invocation_dir: py.path.local, invocation_path: Path) -> None:
def test_file(self, invocation_path: Path) -> None:
"""File and parts."""
assert resolve_collection_argument(invocation_path, "src/pkg/test.py") == (
invocation_dir / "src/pkg/test.py",
invocation_path / "src/pkg/test.py",
[],
)
assert resolve_collection_argument(invocation_path, "src/pkg/test.py::") == (
invocation_dir / "src/pkg/test.py",
invocation_path / "src/pkg/test.py",
[""],
)
assert resolve_collection_argument(
invocation_path, "src/pkg/test.py::foo::bar"
) == (invocation_dir / "src/pkg/test.py", ["foo", "bar"])
) == (invocation_path / "src/pkg/test.py", ["foo", "bar"])
assert resolve_collection_argument(
invocation_path, "src/pkg/test.py::foo::bar::"
) == (invocation_dir / "src/pkg/test.py", ["foo", "bar", ""])
) == (invocation_path / "src/pkg/test.py", ["foo", "bar", ""])
def test_dir(self, invocation_dir: py.path.local, invocation_path: Path) -> None:
def test_dir(self, invocation_path: Path) -> None:
"""Directory and parts."""
assert resolve_collection_argument(invocation_path, "src/pkg") == (
invocation_dir / "src/pkg",
invocation_path / "src/pkg",
[],
)
@ -156,16 +152,16 @@ class TestResolveCollectionArgument:
):
resolve_collection_argument(invocation_path, "src/pkg::foo::bar")
def test_pypath(self, invocation_dir: py.path.local, invocation_path: Path) -> None:
def test_pypath(self, invocation_path: Path) -> None:
"""Dotted name and parts."""
assert resolve_collection_argument(
invocation_path, "pkg.test", as_pypath=True
) == (invocation_dir / "src/pkg/test.py", [])
) == (invocation_path / "src/pkg/test.py", [])
assert resolve_collection_argument(
invocation_path, "pkg.test::foo::bar", as_pypath=True
) == (invocation_dir / "src/pkg/test.py", ["foo", "bar"])
) == (invocation_path / "src/pkg/test.py", ["foo", "bar"])
assert resolve_collection_argument(invocation_path, "pkg", as_pypath=True) == (
invocation_dir / "src/pkg",
invocation_path / "src/pkg",
[],
)
@ -191,13 +187,11 @@ class TestResolveCollectionArgument:
):
resolve_collection_argument(invocation_path, "foobar", as_pypath=True)
def test_absolute_paths_are_resolved_correctly(
self, invocation_dir: py.path.local, invocation_path: Path
) -> None:
def test_absolute_paths_are_resolved_correctly(self, invocation_path: Path) -> None:
"""Absolute paths resolve back to absolute paths."""
full_path = str(invocation_dir / "src")
full_path = str(invocation_path / "src")
assert resolve_collection_argument(invocation_path, full_path) == (
py.path.local(os.path.abspath("src")),
Path(os.path.abspath("src")),
[],
)
@ -206,7 +200,7 @@ class TestResolveCollectionArgument:
drive, full_path_without_drive = os.path.splitdrive(full_path)
assert resolve_collection_argument(
invocation_path, full_path_without_drive
) == (py.path.local(os.path.abspath("src")), [])
) == (Path(os.path.abspath("src")), [])
def test_module_full_path_without_drive(testdir):

View File

@ -1,3 +1,4 @@
from typing import cast
from typing import List
from typing import Type
@ -73,17 +74,21 @@ def test__check_initialpaths_for_relpath() -> None:
class FakeSession1:
_initialpaths = [cwd]
assert nodes._check_initialpaths_for_relpath(FakeSession1, cwd) == ""
session = cast(pytest.Session, FakeSession1)
assert nodes._check_initialpaths_for_relpath(session, cwd) == ""
sub = cwd.join("file")
class FakeSession2:
_initialpaths = [cwd]
assert nodes._check_initialpaths_for_relpath(FakeSession2, sub) == "file"
session = cast(pytest.Session, FakeSession2)
assert nodes._check_initialpaths_for_relpath(session, sub) == "file"
outside = py.path.local("/outside")
assert nodes._check_initialpaths_for_relpath(FakeSession2, outside) is None
assert nodes._check_initialpaths_for_relpath(session, outside) is None
def test_failure_with_changed_cwd(pytester: Pytester) -> None: