drop usage of py.path.local calls

Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
This commit is contained in:
Ronny Pfannschmidt 2021-02-22 09:43:52 +01:00
parent 22dad53a24
commit 77cb110258
20 changed files with 138 additions and 131 deletions

View File

@ -87,3 +87,9 @@ repos:
xml\.
)
types: [python]
- id: py-path-deprecated
name: py.path usage is deprecated
language: pygrep
entry: \bpy\.path\.local
exclude: docs
types: [python]

View File

@ -31,7 +31,6 @@ from weakref import ref
import attr
import pluggy
import py
import _pytest
from _pytest._code.source import findsource
@ -1230,7 +1229,7 @@ _PLUGGY_DIR = Path(pluggy.__file__.rstrip("oc"))
if _PLUGGY_DIR.name == "__init__.py":
_PLUGGY_DIR = _PLUGGY_DIR.parent
_PYTEST_DIR = Path(_pytest.__file__).parent
_PY_DIR = Path(py.__file__).parent
_PY_DIR = Path(__import__("py").__file__).parent
def filter_traceback(entry: TracebackEntry) -> bool:

View File

@ -13,7 +13,6 @@ from typing import Set
from typing import Union
import attr
import py
from .pathlib import resolve_from_str
from .pathlib import rm_rf
@ -21,6 +20,8 @@ from .reports import CollectReport
from _pytest import nodes
from _pytest._io import TerminalWriter
from _pytest.compat import final
from _pytest.compat import LEGACY_PATH
from _pytest.compat import legacy_path
from _pytest.config import Config
from _pytest.config import ExitCode
from _pytest.config import hookimpl
@ -120,7 +121,7 @@ class Cache:
stacklevel=3,
)
def makedir(self, name: str) -> py.path.local:
def makedir(self, name: str) -> LEGACY_PATH:
"""Return a directory path object with the given name.
If the directory does not yet exist, it will be created. You can use
@ -137,7 +138,7 @@ class Cache:
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 py.path.local(res)
return legacy_path(res)
def _getvaluepath(self, key: str) -> Path:
return self._cachedir.joinpath(self._CACHE_PREFIX_VALUES, Path(key))

View File

@ -32,15 +32,18 @@ if TYPE_CHECKING:
_T = TypeVar("_T")
_S = TypeVar("_S")
#: constant to prepare valuing py.path.local replacements/lazy proxies later on
#: constant to prepare valuing pylib path replacements/lazy proxies later on
# intended for removal in pytest 8.0 or 9.0
LEGACY_PATH = py.path.local
# fmt: off
# intentional space to create a fake difference for the verification
LEGACY_PATH = py.path. local
# fmt: on
def legacy_path(path: Union[str, "os.PathLike[str]"]) -> LEGACY_PATH:
"""Internal wrapper to prepare lazy proxies for py.path.local instances"""
return py.path.local(path)
"""Internal wrapper to prepare lazy proxies for legacy_path instances"""
return LEGACY_PATH(path)
# fmt: off

View File

@ -32,7 +32,6 @@ from typing import TYPE_CHECKING
from typing import Union
import attr
import py
from pluggy import HookimplMarker
from pluggy import HookspecMarker
from pluggy import PluginManager
@ -48,6 +47,8 @@ from _pytest._code import filter_traceback
from _pytest._io import TerminalWriter
from _pytest.compat import final
from _pytest.compat import importlib_metadata
from _pytest.compat import LEGACY_PATH
from _pytest.compat import legacy_path
from _pytest.outcomes import fail
from _pytest.outcomes import Skipped
from _pytest.pathlib import absolutepath
@ -937,15 +938,15 @@ class Config:
self.cache: Optional[Cache] = None
@property
def invocation_dir(self) -> py.path.local:
def invocation_dir(self) -> LEGACY_PATH:
"""The directory from which pytest was invoked.
Prefer to use :attr:`invocation_params.dir <InvocationParams.dir>`,
which is a :class:`pathlib.Path`.
:type: py.path.local
:type: LEGACY_PATH
"""
return py.path.local(str(self.invocation_params.dir))
return legacy_path(str(self.invocation_params.dir))
@property
def rootpath(self) -> Path:
@ -958,14 +959,14 @@ class Config:
return self._rootpath
@property
def rootdir(self) -> py.path.local:
def rootdir(self) -> LEGACY_PATH:
"""The path to the :ref:`rootdir <rootdir>`.
Prefer to use :attr:`rootpath`, which is a :class:`pathlib.Path`.
:type: py.path.local
:type: LEGACY_PATH
"""
return py.path.local(str(self.rootpath))
return legacy_path(str(self.rootpath))
@property
def inipath(self) -> Optional[Path]:
@ -978,14 +979,14 @@ class Config:
return self._inipath
@property
def inifile(self) -> Optional[py.path.local]:
def inifile(self) -> Optional[LEGACY_PATH]:
"""The path to the :ref:`configfile <configfiles>`.
Prefer to use :attr:`inipath`, which is a :class:`pathlib.Path`.
:type: Optional[py.path.local]
:type: Optional[LEGACY_PATH]
"""
return py.path.local(str(self.inipath)) if self.inipath else None
return legacy_path(str(self.inipath)) if self.inipath else None
def add_cleanup(self, func: Callable[[], None]) -> None:
"""Add a function to be called when the config object gets out of
@ -1420,7 +1421,7 @@ class Config:
assert self.inipath is not None
dp = self.inipath.parent
input_values = shlex.split(value) if isinstance(value, str) else value
return [py.path.local(str(dp / x)) for x in input_values]
return [legacy_path(str(dp / x)) for x in input_values]
elif type == "args":
return shlex.split(value) if isinstance(value, str) else value
elif type == "linelist":
@ -1446,7 +1447,7 @@ class Config:
for relroot in relroots:
if isinstance(relroot, Path):
pass
elif isinstance(relroot, py.path.local):
elif isinstance(relroot, LEGACY_PATH):
relroot = Path(relroot)
else:
relroot = relroot.replace("/", os.sep)

View File

@ -92,7 +92,7 @@ ARGUMENT_TYPE_STR = UnformattedWarning(
NODE_FSPATH = UnformattedWarning(
PytestDeprecationWarning,
"{type}.fspath is deprecated and will be replaced by {type}.path.\n"
"see TODO;URL for details on replacing py.path.local with pathlib.Path",
"see https://docs.pytest.org/en/latest/deprecations.html#node-fspath-in-favor-of-pathlib-and-node-path",
)
# You want to make some `__init__` or function "private".

View File

@ -22,14 +22,13 @@ from typing import Type
from typing import TYPE_CHECKING
from typing import Union
import py.path
import pytest
from _pytest import outcomes
from _pytest._code.code import ExceptionInfo
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
@ -123,7 +122,7 @@ def pytest_unconfigure() -> None:
def pytest_collect_file(
fspath: Path,
path: py.path.local,
path: LEGACY_PATH,
parent: Collector,
) -> Optional[Union["DoctestModule", "DoctestTextfile"]]:
config = parent.config

View File

@ -11,7 +11,6 @@ from typing import Tuple
from typing import TYPE_CHECKING
from typing import Union
import py.path
from pluggy import HookspecMarker
from _pytest.deprecated import WARNING_CAPTURED_HOOK
@ -42,6 +41,7 @@ if TYPE_CHECKING:
from _pytest.reports import TestReport
from _pytest.runner import CallInfo
from _pytest.terminal import TerminalReporter
from _pytest.compat import LEGACY_PATH
hookspec = HookspecMarker("pytest")
@ -263,7 +263,7 @@ def pytest_collection_finish(session: "Session") -> None:
@hookspec(firstresult=True)
def pytest_ignore_collect(
fspath: Path, path: py.path.local, config: "Config"
fspath: Path, path: "LEGACY_PATH", config: "Config"
) -> Optional[bool]:
"""Return True to prevent considering this path for collection.
@ -273,7 +273,7 @@ def pytest_ignore_collect(
Stops at first non-None result, see :ref:`firstresult`.
:param pathlib.Path fspath: The path to analyze.
:param py.path.local path: The path to analyze.
:param LEGACY_PATH path: The path to analyze.
:param _pytest.config.Config config: The pytest config object.
.. versionchanged:: 6.3.0
@ -283,14 +283,14 @@ def pytest_ignore_collect(
def pytest_collect_file(
fspath: Path, path: py.path.local, parent: "Collector"
fspath: Path, path: "LEGACY_PATH", parent: "Collector"
) -> "Optional[Collector]":
"""Create a Collector for the given path, or None if not relevant.
The new node needs to have the specified ``parent`` as a parent.
:param pathlib.Path fspath: The path to analyze.
:param py.path.local path: The path to collect.
:param LEGACY_PATH path: The path to collect.
.. versionchanged:: 6.3.0
The ``fspath`` parameter was added as a :class:`pathlib.Path`
@ -335,7 +335,7 @@ def pytest_make_collect_report(collector: "Collector") -> "Optional[CollectRepor
@hookspec(firstresult=True)
def pytest_pycollect_makemodule(
fspath: Path, path: py.path.local, parent
fspath: Path, path: "LEGACY_PATH", parent
) -> Optional["Module"]:
"""Return a Module collector or None for the given path.
@ -346,7 +346,7 @@ def pytest_pycollect_makemodule(
Stops at first non-None result, see :ref:`firstresult`.
:param pathlib.Path fspath: The path of the module to collect.
:param py.path.local path: The path of the module to collect.
:param legacy_path path: The path of the module to collect.
.. versionchanged:: 6.3.0
The ``fspath`` parameter was added as a :class:`pathlib.Path`
@ -676,13 +676,13 @@ def pytest_assertion_pass(item: "Item", lineno: int, orig: str, expl: str) -> No
def pytest_report_header(
config: "Config", startpath: Path, startdir: py.path.local
config: "Config", startpath: Path, startdir: "LEGACY_PATH"
) -> Union[str, List[str]]:
"""Return a string or list of strings to be displayed as header info for terminal reporting.
:param _pytest.config.Config config: The pytest config object.
:param Path startpath: The starting dir.
:param py.path.local startdir: The starting dir.
:param LEGACY_PATH startdir: The starting dir.
.. note::
@ -706,7 +706,7 @@ def pytest_report_header(
def pytest_report_collectionfinish(
config: "Config",
startpath: Path,
startdir: py.path.local,
startdir: "LEGACY_PATH",
items: Sequence["Item"],
) -> Union[str, List[str]]:
"""Return a string or list of strings to be displayed after collection
@ -718,7 +718,7 @@ def pytest_report_collectionfinish(
:param _pytest.config.Config config: The pytest config object.
:param Path startpath: The starting path.
:param py.path.local startdir: The starting dir.
:param LEGACY_PATH startdir: The starting dir.
:param items: List of pytest items that are going to be executed; this list should not be modified.
.. note::

View File

@ -21,11 +21,11 @@ from typing import TYPE_CHECKING
from typing import Union
import attr
import py
import _pytest._code
from _pytest import nodes
from _pytest.compat import final
from _pytest.compat import legacy_path
from _pytest.config import Config
from _pytest.config import directory_arg
from _pytest.config import ExitCode
@ -543,7 +543,7 @@ class Session(nodes.FSCollector):
if direntry.name == "__pycache__":
return False
fspath = Path(direntry.path)
path = py.path.local(fspath)
path = legacy_path(fspath)
ihook = self.gethookproxy(fspath.parent)
if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config):
return False
@ -555,7 +555,7 @@ class Session(nodes.FSCollector):
def _collectfile(
self, fspath: Path, handle_dupes: bool = True
) -> Sequence[nodes.Collector]:
path = py.path.local(fspath)
path = legacy_path(fspath)
assert (
fspath.is_file()
), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(

View File

@ -16,8 +16,6 @@ from typing import TYPE_CHECKING
from typing import TypeVar
from typing import Union
import py
import _pytest._code
from _pytest._code import getfslineno
from _pytest._code.code import ExceptionInfo
@ -145,7 +143,7 @@ class Node(metaclass=NodeMeta):
parent: "Optional[Node]" = None,
config: Optional[Config] = None,
session: "Optional[Session]" = None,
fspath: Optional[py.path.local] = None,
fspath: Optional[LEGACY_PATH] = None,
path: Optional[Path] = None,
nodeid: Optional[str] = None,
) -> None:
@ -199,13 +197,13 @@ class Node(metaclass=NodeMeta):
self._store = Store()
@property
def fspath(self):
"""(deprecated) returns a py.path.local copy of self.path"""
def fspath(self) -> LEGACY_PATH:
"""(deprecated) returns a legacy_path copy of self.path"""
warnings.warn(NODE_FSPATH.format(type=type(self).__name__), stacklevel=2)
return py.path.local(self.path)
return legacy_path(self.path)
@fspath.setter
def fspath(self, value: py.path.local):
def fspath(self, value: LEGACY_PATH) -> None:
warnings.warn(NODE_FSPATH.format(type=type(self).__name__), stacklevel=2)
self.path = Path(value)
@ -464,7 +462,7 @@ def get_fslocation_from_item(node: "Node") -> Tuple[Union[str, Path], Optional[i
* "obj": a Python object that the node wraps.
* "fspath": just a path
:rtype: A tuple of (str|py.path.local, int) with filename and line number.
:rtype: A tuple of (str|Path, int) with filename and line number.
"""
# See Item.location.
location: Optional[Tuple[str, Optional[int], str]] = getattr(node, "location", None)
@ -520,10 +518,10 @@ class Collector(Node):
def _check_initialpaths_for_relpath(
session: "Session", fspath: py.path.local
session: "Session", fspath: LEGACY_PATH
) -> Optional[str]:
for initial_path in session._initialpaths:
initial_path_ = py.path.local(initial_path)
initial_path_ = legacy_path(initial_path)
if fspath.common(initial_path_) == initial_path_:
return fspath.relto(initial_path_)
return None
@ -532,7 +530,7 @@ def _check_initialpaths_for_relpath(
class FSCollector(Collector):
def __init__(
self,
fspath: Optional[py.path.local],
fspath: Optional[LEGACY_PATH],
path: Optional[Path],
parent=None,
config: Optional[Config] = None,
@ -571,7 +569,7 @@ class FSCollector(Collector):
cls,
parent,
*,
fspath: Optional[py.path.local] = None,
fspath: Optional[LEGACY_PATH] = None,
path: Optional[Path] = None,
**kw,
):
@ -638,8 +636,10 @@ class Item(Node):
if content:
self._report_sections.append((when, key, content))
def reportinfo(self) -> Tuple[Union[py.path.local, str], Optional[int], str]:
return self.fspath, None, ""
def reportinfo(self) -> Tuple[Union[LEGACY_PATH, str], Optional[int], str]:
# TODO: enable Path objects in reportinfo
return legacy_path(self.path), None, ""
@cached_property
def location(self) -> Tuple[str, Optional[int], str]:

View File

@ -34,7 +34,6 @@ from typing import Union
from weakref import WeakKeyDictionary
import attr
import py
from iniconfig import IniConfig
from iniconfig import SectionWrapper
@ -42,6 +41,8 @@ from _pytest import timing
from _pytest._code import Source
from _pytest.capture import _get_multicapture
from _pytest.compat import final
from _pytest.compat import LEGACY_PATH
from _pytest.compat import legacy_path
from _pytest.compat import NOTSET
from _pytest.compat import NotSetType
from _pytest.config import _PluggyPlugin
@ -475,7 +476,7 @@ def pytester(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> "Pyt
def testdir(pytester: "Pytester") -> "Testdir":
"""
Identical to :fixture:`pytester`, and provides an instance whose methods return
legacy ``py.path.local`` objects instead when applicable.
legacy ``LEGACY_PATH`` objects instead when applicable.
New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
"""
@ -934,10 +935,10 @@ class Pytester:
example_path = example_dir.joinpath(name)
if example_path.is_dir() and not example_path.joinpath("__init__.py").is_file():
# TODO: py.path.local.copy can copy files to existing directories,
# TODO: legacy_path.copy can copy files to existing directories,
# while with shutil.copytree the destination directory cannot exist,
# we will need to roll our own in order to drop py.path.local completely
py.path.local(example_path).copy(py.path.local(self.path))
# we will need to roll our own in order to drop legacy_path completely
legacy_path(example_path).copy(legacy_path(self.path))
return self.path
elif example_path.is_file():
result = self.path.joinpath(example_path.name)
@ -958,12 +959,12 @@ class Pytester:
:param _pytest.config.Config config:
A pytest config.
See :py:meth:`parseconfig` and :py:meth:`parseconfigure` for creating it.
:param py.path.local arg:
:param os.PathLike[str] arg:
Path to the file.
"""
session = Session.from_config(config)
assert "::" not in str(arg)
p = py.path.local(arg)
p = legacy_path(arg)
config.hook.pytest_sessionstart(session=session)
res = session.perform_collect([str(p)], genitems=False)[0]
config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK)
@ -975,7 +976,7 @@ class Pytester:
This is like :py:meth:`getnode` but uses :py:meth:`parseconfigure` to
create the (configured) pytest Config instance.
:param py.path.local path: Path to the file.
:param os.PathLike[str] path: Path to the file.
"""
path = Path(path)
config = self.parseconfigure(path)
@ -1520,10 +1521,10 @@ class LineComp:
@attr.s(repr=False, str=False, init=False)
class Testdir:
"""
Similar to :class:`Pytester`, but this class works with legacy py.path.local objects instead.
Similar to :class:`Pytester`, but this class works with legacy legacy_path objects instead.
All methods just forward to an internal :class:`Pytester` instance, converting results
to `py.path.local` objects as necessary.
to `legacy_path` objects as necessary.
"""
__test__ = False
@ -1537,13 +1538,13 @@ class Testdir:
self._pytester = pytester
@property
def tmpdir(self) -> py.path.local:
def tmpdir(self) -> LEGACY_PATH:
"""Temporary directory where tests are executed."""
return py.path.local(self._pytester.path)
return legacy_path(self._pytester.path)
@property
def test_tmproot(self) -> py.path.local:
return py.path.local(self._pytester._test_tmproot)
def test_tmproot(self) -> LEGACY_PATH:
return legacy_path(self._pytester._test_tmproot)
@property
def request(self):
@ -1573,7 +1574,7 @@ class Testdir:
"""See :meth:`Pytester._finalize`."""
return self._pytester._finalize()
def makefile(self, ext, *args, **kwargs) -> py.path.local:
def makefile(self, ext, *args, **kwargs) -> LEGACY_PATH:
"""See :meth:`Pytester.makefile`."""
if ext and not ext.startswith("."):
# pytester.makefile is going to throw a ValueError in a way that
@ -1583,47 +1584,47 @@ class Testdir:
# allowed this, we will prepend "." as a workaround to avoid breaking
# testdir usage that worked before
ext = "." + ext
return py.path.local(str(self._pytester.makefile(ext, *args, **kwargs)))
return legacy_path(self._pytester.makefile(ext, *args, **kwargs))
def makeconftest(self, source) -> py.path.local:
def makeconftest(self, source) -> LEGACY_PATH:
"""See :meth:`Pytester.makeconftest`."""
return py.path.local(str(self._pytester.makeconftest(source)))
return legacy_path(self._pytester.makeconftest(source))
def makeini(self, source) -> py.path.local:
def makeini(self, source) -> LEGACY_PATH:
"""See :meth:`Pytester.makeini`."""
return py.path.local(str(self._pytester.makeini(source)))
return legacy_path(self._pytester.makeini(source))
def getinicfg(self, source: str) -> SectionWrapper:
"""See :meth:`Pytester.getinicfg`."""
return self._pytester.getinicfg(source)
def makepyprojecttoml(self, source) -> py.path.local:
def makepyprojecttoml(self, source) -> LEGACY_PATH:
"""See :meth:`Pytester.makepyprojecttoml`."""
return py.path.local(str(self._pytester.makepyprojecttoml(source)))
return legacy_path(self._pytester.makepyprojecttoml(source))
def makepyfile(self, *args, **kwargs) -> py.path.local:
def makepyfile(self, *args, **kwargs) -> LEGACY_PATH:
"""See :meth:`Pytester.makepyfile`."""
return py.path.local(str(self._pytester.makepyfile(*args, **kwargs)))
return legacy_path(self._pytester.makepyfile(*args, **kwargs))
def maketxtfile(self, *args, **kwargs) -> py.path.local:
def maketxtfile(self, *args, **kwargs) -> LEGACY_PATH:
"""See :meth:`Pytester.maketxtfile`."""
return py.path.local(str(self._pytester.maketxtfile(*args, **kwargs)))
return legacy_path(self._pytester.maketxtfile(*args, **kwargs))
def syspathinsert(self, path=None) -> None:
"""See :meth:`Pytester.syspathinsert`."""
return self._pytester.syspathinsert(path)
def mkdir(self, name) -> py.path.local:
def mkdir(self, name) -> LEGACY_PATH:
"""See :meth:`Pytester.mkdir`."""
return py.path.local(str(self._pytester.mkdir(name)))
return legacy_path(self._pytester.mkdir(name))
def mkpydir(self, name) -> py.path.local:
def mkpydir(self, name) -> LEGACY_PATH:
"""See :meth:`Pytester.mkpydir`."""
return py.path.local(str(self._pytester.mkpydir(name)))
return legacy_path(self._pytester.mkpydir(name))
def copy_example(self, name=None) -> py.path.local:
def copy_example(self, name=None) -> LEGACY_PATH:
"""See :meth:`Pytester.copy_example`."""
return py.path.local(str(self._pytester.copy_example(name)))
return legacy_path(self._pytester.copy_example(name))
def getnode(self, config: Config, arg) -> Optional[Union[Item, Collector]]:
"""See :meth:`Pytester.getnode`."""

View File

@ -26,8 +26,6 @@ from typing import Tuple
from typing import TYPE_CHECKING
from typing import Union
import py
import _pytest
from _pytest import fixtures
from _pytest import nodes
@ -45,6 +43,8 @@ from _pytest.compat import getimfunc
from _pytest.compat import getlocation
from _pytest.compat import is_async_function
from _pytest.compat import is_generator
from _pytest.compat import LEGACY_PATH
from _pytest.compat import legacy_path
from _pytest.compat import NOTSET
from _pytest.compat import REGEX_TYPE
from _pytest.compat import safe_getattr
@ -189,7 +189,7 @@ def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]:
def pytest_collect_file(
fspath: Path, path: py.path.local, parent: nodes.Collector
fspath: Path, path: LEGACY_PATH, parent: nodes.Collector
) -> Optional["Module"]:
if fspath.suffix == ".py":
if not parent.session.isinitpath(fspath):
@ -210,7 +210,7 @@ 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: py.path.local, parent) -> "Module":
def pytest_pycollect_makemodule(fspath: Path, path: LEGACY_PATH, parent) -> "Module":
if fspath.name == "__init__.py":
pkg: Package = Package.from_parent(parent, fspath=path)
return pkg
@ -321,7 +321,7 @@ class PyobjMixin(nodes.Node):
parts.reverse()
return ".".join(parts)
def reportinfo(self) -> Tuple[Union[py.path.local, str], int, str]:
def reportinfo(self) -> Tuple[Union[LEGACY_PATH, str], int, str]:
# XXX caching?
obj = self.obj
compat_co_firstlineno = getattr(obj, "compat_co_firstlineno", None)
@ -330,12 +330,12 @@ class PyobjMixin(nodes.Node):
file_path = sys.modules[obj.__module__].__file__
if file_path.endswith(".pyc"):
file_path = file_path[:-1]
fspath: Union[py.path.local, str] = file_path
fspath: Union[LEGACY_PATH, str] = file_path
lineno = compat_co_firstlineno
else:
path, lineno = getfslineno(obj)
if isinstance(path, Path):
fspath = py.path.local(path)
fspath = legacy_path(path)
else:
fspath = path
modpath = self.getmodpath()
@ -624,7 +624,7 @@ class Module(nodes.File, PyCollector):
class Package(Module):
def __init__(
self,
fspath: Optional[py.path.local],
fspath: Optional[LEGACY_PATH],
parent: nodes.Collector,
# NOTE: following args are unused:
config=None,
@ -675,7 +675,7 @@ class Package(Module):
if direntry.name == "__pycache__":
return False
fspath = Path(direntry.path)
path = py.path.local(fspath)
path = legacy_path(fspath)
ihook = self.session.gethookproxy(fspath.parent)
if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config):
return False
@ -687,7 +687,7 @@ class Package(Module):
def _collectfile(
self, fspath: Path, handle_dupes: bool = True
) -> Sequence[nodes.Collector]:
path = py.path.local(fspath)
path = legacy_path(fspath)
assert (
fspath.is_file()
), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(

View File

@ -15,7 +15,6 @@ from typing import TypeVar
from typing import Union
import attr
import py
from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionInfo
@ -30,6 +29,7 @@ from _pytest._code.code import ReprTraceback
from _pytest._code.code import TerminalRepr
from _pytest._io import TerminalWriter
from _pytest.compat import final
from _pytest.compat import LEGACY_PATH
from _pytest.config import Config
from _pytest.nodes import Collector
from _pytest.nodes import Item
@ -500,7 +500,7 @@ def _report_to_json(report: BaseReport) -> Dict[str, Any]:
else:
d["longrepr"] = report.longrepr
for name in d:
if isinstance(d[name], (py.path.local, Path)):
if isinstance(d[name], (LEGACY_PATH, Path)):
d[name] = str(d[name])
elif name == "result":
d[name] = None # for now

View File

@ -6,13 +6,14 @@ from pathlib import Path
from typing import Optional
import attr
import py
from .pathlib import ensure_reset_dir
from .pathlib import LOCK_TIMEOUT
from .pathlib import make_numbered_dir
from .pathlib import make_numbered_dir_with_cleanup
from _pytest.compat import final
from _pytest.compat import LEGACY_PATH
from _pytest.compat import legacy_path
from _pytest.config import Config
from _pytest.deprecated import check_ispytest
from _pytest.fixtures import fixture
@ -133,7 +134,7 @@ class TempPathFactory:
@final
@attr.s(init=False)
class TempdirFactory:
"""Backward comptibility wrapper that implements :class:``py.path.local``
"""Backward comptibility wrapper that implements :class:``_pytest.compat.LEGACY_PATH``
for :class:``TempPathFactory``."""
_tmppath_factory = attr.ib(type=TempPathFactory)
@ -144,13 +145,13 @@ class TempdirFactory:
check_ispytest(_ispytest)
self._tmppath_factory = tmppath_factory
def mktemp(self, basename: str, numbered: bool = True) -> py.path.local:
"""Same as :meth:`TempPathFactory.mktemp`, but returns a ``py.path.local`` object."""
return py.path.local(self._tmppath_factory.mktemp(basename, numbered).resolve())
def mktemp(self, basename: str, numbered: bool = True) -> LEGACY_PATH:
"""Same as :meth:`TempPathFactory.mktemp`, but returns a ``_pytest.compat.LEGACY_PATH`` object."""
return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve())
def getbasetemp(self) -> py.path.local:
def getbasetemp(self) -> LEGACY_PATH:
"""Backward compat wrapper for ``_tmppath_factory.getbasetemp``."""
return py.path.local(self._tmppath_factory.getbasetemp().resolve())
return legacy_path(self._tmppath_factory.getbasetemp().resolve())
def get_user() -> Optional[str]:
@ -202,7 +203,7 @@ def _mk_tmp(request: FixtureRequest, factory: TempPathFactory) -> Path:
@fixture
def tmpdir(tmp_path: Path) -> py.path.local:
def tmpdir(tmp_path: Path) -> LEGACY_PATH:
"""Return a temporary directory path object which is unique to each test
function invocation, created as a sub directory of the base temporary
directory.
@ -212,11 +213,11 @@ def tmpdir(tmp_path: Path) -> py.path.local:
``--basetemp`` is used then it is cleared each session. See :ref:`base
temporary directory`.
The returned object is a `py.path.local`_ path object.
The returned object is a `legacy_path`_ object.
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
.. _legacy_path: https://py.readthedocs.io/en/latest/path.html
"""
return py.path.local(tmp_path)
return legacy_path(tmp_path)
@fixture

View File

@ -6,8 +6,6 @@ import textwrap
from pathlib import Path
from typing import List
import py.path
import pytest
from _pytest.config import ExitCode
from _pytest.fixtures import FixtureRequest
@ -369,9 +367,10 @@ class TestCustomConftests:
def test_collectignore_exclude_on_option(self, pytester: Pytester) -> None:
pytester.makeconftest(
"""
import py
# potentially avoid dependency on pylib
from _pytest.compat import legacy_path
from pathlib import Path
collect_ignore = [py.path.local('hello'), 'test_world.py', Path('bye')]
collect_ignore = [legacy_path('hello'), 'test_world.py', Path('bye')]
def pytest_addoption(parser):
parser.addoption("--XX", action="store_true", default=False)
def pytest_configure(config):
@ -1347,6 +1346,7 @@ def test_fscollector_from_parent(pytester: Pytester, request: FixtureRequest) ->
Context: https://github.com/pytest-dev/pytest-cpp/pull/47
"""
from _pytest.compat import legacy_path
class MyCollector(pytest.File):
def __init__(self, *k, x, **kw):
@ -1354,7 +1354,7 @@ def test_fscollector_from_parent(pytester: Pytester, request: FixtureRequest) ->
self.x = x
collector = MyCollector.from_parent(
parent=request.session, fspath=py.path.local(pytester.path) / "foo", x=10
parent=request.session, fspath=legacy_path(pytester.path) / "foo", x=10
)
assert collector.x == 10

View File

@ -205,7 +205,7 @@ class TestResolveCollectionArgument:
def test_module_full_path_without_drive(pytester: Pytester) -> None:
"""Collect and run test using full path except for the drive letter (#7628).
Passing a full path without a drive letter would trigger a bug in py.path.local
Passing a full path without a drive letter would trigger a bug in legacy_path
where it would keep the full path without the drive letter around, instead of resolving
to the full path, resulting in fixtures node ids not matching against test node ids correctly.
"""

View File

@ -3,10 +3,9 @@ from typing import cast
from typing import List
from typing import Type
import py
import pytest
from _pytest import nodes
from _pytest.compat import legacy_path
from _pytest.pytester import Pytester
from _pytest.warning_types import PytestWarning
@ -77,7 +76,7 @@ def test__check_initialpaths_for_relpath() -> None:
session = cast(pytest.Session, FakeSession1)
assert nodes._check_initialpaths_for_relpath(session, py.path.local(cwd)) == ""
assert nodes._check_initialpaths_for_relpath(session, legacy_path(cwd)) == ""
sub = cwd / "file"
@ -86,9 +85,9 @@ def test__check_initialpaths_for_relpath() -> None:
session = cast(pytest.Session, FakeSession2)
assert nodes._check_initialpaths_for_relpath(session, py.path.local(sub)) == "file"
assert nodes._check_initialpaths_for_relpath(session, legacy_path(sub)) == "file"
outside = py.path.local("/outside")
outside = legacy_path("/outside")
assert nodes._check_initialpaths_for_relpath(session, outside) is None

View File

@ -4,9 +4,8 @@ import shlex
import subprocess
import sys
import py
import pytest
from _pytest.compat import legacy_path
from _pytest.config import argparsing as parseopt
from _pytest.config.exceptions import UsageError
from _pytest.monkeypatch import MonkeyPatch
@ -124,11 +123,11 @@ class TestParser:
assert not getattr(args, parseopt.FILE_OR_DIR)
def test_parse2(self, parser: parseopt.Parser) -> None:
args = parser.parse([py.path.local()])
assert getattr(args, parseopt.FILE_OR_DIR)[0] == py.path.local()
args = parser.parse([legacy_path(".")])
assert getattr(args, parseopt.FILE_OR_DIR)[0] == legacy_path(".")
def test_parse_known_args(self, parser: parseopt.Parser) -> None:
parser.parse_known_args([py.path.local()])
parser.parse_known_args([legacy_path(".")])
parser.addoption("--hello", action="store_true")
ns = parser.parse_known_args(["x", "--y", "--hello", "this"])
assert ns.hello

View File

@ -7,9 +7,8 @@ from textwrap import dedent
from types import ModuleType
from typing import Generator
import py
import pytest
from _pytest.compat import legacy_path
from _pytest.monkeypatch import MonkeyPatch
from _pytest.pathlib import bestrelpath
from _pytest.pathlib import commonpath
@ -28,14 +27,14 @@ from _pytest.tmpdir import TempPathFactory
class TestFNMatcherPort:
"""Test that our port of py.common.FNMatcher (fnmatch_ex) produces the
same results as the original py.path.local.fnmatch method."""
same results as the original legacy_path.fnmatch method."""
@pytest.fixture(params=["pathlib", "py.path"])
def match(self, request):
if request.param == "py.path":
def match_(pattern, path):
return py.path.local(path).fnmatch(pattern)
return legacy_path(path).fnmatch(pattern)
else:
assert request.param == "pathlib"

View File

@ -1,11 +1,10 @@
from typing import Sequence
from typing import Union
import py.path
import pytest
from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionRepr
from _pytest.compat import legacy_path
from _pytest.config import Config
from _pytest.pytester import Pytester
from _pytest.reports import CollectReport
@ -237,7 +236,7 @@ class TestReportSerialization:
reports = reprec.getreports("pytest_runtest_logreport")
assert len(reports) == 3
test_a_call = reports[1]
test_a_call.path1 = py.path.local(pytester.path) # type: ignore[attr-defined]
test_a_call.path1 = legacy_path(pytester.path) # type: ignore[attr-defined]
test_a_call.path2 = pytester.path # type: ignore[attr-defined]
data = test_a_call._to_json()
assert data["path1"] == str(pytester.path)