def _check_initialpaths_for_relpath(session: "Session", fspath: LEGACY_PATH) -> Optional[str]: for initial_path in session._initialpaths: initial_path_ = legacy_path(initial_path) if fspath.common(initial_path_) == initial_path_: return fspath.relto(initial_path_) return None
def _collectfile(self, fspath: Path, handle_dupes: bool = True) -> Sequence[nodes.Collector]: path = legacy_path(fspath) assert (fspath.is_file( )), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( fspath, fspath.is_dir(), fspath.exists(), fspath.is_symlink()) ihook = self.gethookproxy(fspath) if not self.isinitpath(fspath): if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config): return () if handle_dupes: keepduplicates = self.config.getoption("keepduplicates") if not keepduplicates: duplicate_paths = self.config.pluginmanager._duplicatepaths if fspath in duplicate_paths: return () else: duplicate_paths.add(fspath) return ihook.pytest_collect_file( fspath=fspath, path=path, parent=self) # type: ignore[no-any-return]
def test_hookproxy_warnings_for_pathlib(tmp_path, hooktype, request): path = legacy_path(tmp_path) PATH_WARN_MATCH = r".*path: py\.path\.local\) argument is deprecated, please use \(collection_path: pathlib\.Path.*" if hooktype == "ihook": hooks = request.node.ihook else: hooks = request.config.hook with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r: l1 = sys._getframe().f_lineno hooks.pytest_ignore_collect(config=request.config, path=path, collection_path=tmp_path) l2 = sys._getframe().f_lineno (record, ) = r assert record.filename == __file__ assert l1 < record.lineno < l2 hooks.pytest_ignore_collect(config=request.config, collection_path=tmp_path) # Passing entirely *different* paths is an outright error. with pytest.raises(ValueError, match=r"path.*fspath.*need to be equal"): with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r: hooks.pytest_ignore_collect(config=request.config, path=path, collection_path=Path("/bla/bla"))
def test_subclassing_both_item_and_collector_deprecated( request, tmp_path: Path) -> None: """ Verifies we warn on diamond inheritance as well as correctly managing legacy inheritance ctors with missing args as found in plugins """ with pytest.warns( PytestWarning, match= ("(?m)SoWrong is an Item subclass and should not be a collector, however its bases File are collectors.\n" "Please split the Collectors and the Item into separate node types.\n.*" ), ): class SoWrong(nodes.File, nodes.Item): def __init__(self, fspath, parent): """Legacy ctor with legacy call # don't wana see""" super().__init__(fspath, parent) with pytest.warns( PytestWarning, match=".*SoWrong.* not using a cooperative constructor.*"): SoWrong.from_parent(request.session, fspath=legacy_path(tmp_path / "broken.txt"))
def test_subclassing_both_item_and_collector_deprecated( request, tmp_path: Path) -> None: """ Verifies we warn on diamond inheritance as well as correctly managing legacy inheritance constructors with missing args as found in plugins. """ # We do not expect any warnings messages to issued during class definition. with warnings.catch_warnings(): warnings.simplefilter("error") class SoWrong(nodes.Item, nodes.File): def __init__(self, fspath, parent): """Legacy ctor with legacy call # don't wana see""" super().__init__(fspath, parent) with pytest.warns(PytestWarning) as rec: SoWrong.from_parent(request.session, fspath=legacy_path(tmp_path / "broken.txt")) messages = [str(x.message) for x in rec] assert any( re.search(".*SoWrong.* not using a cooperative constructor.*", x) for x in messages) assert any( re.search("(?m)SoWrong .* should not be a collector", x) for x in messages)
def stardir(self) -> LEGACY_PATH: """The path from which pytest was invoked. Prefer to use ``startpath`` which is a :class:`pathlib.Path`. :type: LEGACY_PATH """ return legacy_path(self.startpath)
def _imply_path(path: Optional[Path], fspath: Optional[LEGACY_PATH]) -> Tuple[Path, LEGACY_PATH]: if path is not None: if fspath is not None: _check_path(path, fspath) else: fspath = legacy_path(path) return path, fspath else: assert fspath is not None return Path(fspath), fspath
def test_node_ctor_fspath_argument_is_deprecated(pytester: Pytester) -> None: mod = pytester.getmodulecol("") with pytest.warns( pytest.PytestDeprecationWarning, match=re.escape("The (fspath: py.path.local) argument to File is deprecated."), ): pytest.File.from_parent( parent=mod.parent, fspath=legacy_path("bla"), )
def _recurse(self, direntry: "os.DirEntry[str]") -> bool: if direntry.name == "__pycache__": return False fspath = Path(direntry.path) path = legacy_path(fspath) ihook = self.gethookproxy(fspath.parent) if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config): return False norecursepatterns = self.config.getini("norecursedirs") if any(fnmatch_ex(pat, fspath) for pat in norecursepatterns): return False return True
def test__check_initialpaths_for_relpath() -> None: """Ensure that it handles dirs, and does not always use dirname.""" cwd = Path.cwd() class FakeSession1: _initialpaths = frozenset({cwd}) session = cast(pytest.Session, FakeSession1) assert nodes._check_initialpaths_for_relpath(session, legacy_path(cwd)) == "" sub = cwd / "file" class FakeSession2: _initialpaths = frozenset({cwd}) session = cast(pytest.Session, FakeSession2) assert nodes._check_initialpaths_for_relpath(session, legacy_path(sub)) == "file" outside = legacy_path("/outside") assert nodes._check_initialpaths_for_relpath(session, outside) is None
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. By default, a new base temporary directory is created each test session, and old bases are removed after 3 sessions, to aid in debugging. If ``--basetemp`` is used then it is cleared each session. See :ref:`base temporary directory`. The returned object is a `legacy_path`_ object. .. _legacy_path: https://py.readthedocs.io/en/latest/path.html """ return legacy_path(tmp_path)
def _imply_path(path: Optional[Path], fspath: Optional[LEGACY_PATH]) -> Tuple[Path, LEGACY_PATH]: if path is not None: if fspath is not None: if Path(fspath) != path: raise ValueError( f"Path({fspath!r}) != {path!r}\n" "if both path and fspath are given they need to be equal") assert Path(fspath) == path, f"{fspath} != {path}" else: fspath = legacy_path(path) return path, fspath else: assert fspath is not None return Path(fspath), fspath
def test_paths_support(self, pytester: Pytester) -> None: """Report attributes which are py.path or pathlib objects should become strings.""" pytester.makepyfile( """ def test_a(): assert False """ ) reprec = pytester.inline_run() reports = reprec.getreports("pytest_runtest_logreport") assert len(reports) == 3 test_a_call = reports[1] 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) assert data["path2"] == str(pytester.path)
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 it to manage files to e.g. store/retrieve database dumps across test sessions. :param name: Must be a string not containing a ``/`` separator. Make sure the name contains your plugin or application identifiers to prevent clashes with other cache users. """ path = Path(name) if len(path.parts) > 1: 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)
def test_hookproxy_warnings_for_fspath(tmp_path, hooktype, request): path = legacy_path(tmp_path) PATH_WARN_MATCH = r".*path: py\.path\.local\) argument is deprecated, please use \(fspath: pathlib\.Path.*" if hooktype == "ihook": hooks = request.node.ihook else: hooks = request.config.hook with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r: l1 = sys._getframe().f_lineno hooks.pytest_ignore_collect(config=request.config, path=path, fspath=tmp_path) l2 = sys._getframe().f_lineno (record, ) = r assert record.filename == __file__ assert l1 < record.lineno < l2 hooks.pytest_ignore_collect(config=request.config, fspath=tmp_path)
def test_parse2(self, parser: parseopt.Parser) -> None: args = parser.parse([legacy_path(".")]) assert getattr(args, parseopt.FILE_OR_DIR)[0] == legacy_path(".")
def getbasetemp(self) -> LEGACY_PATH: """Backward compat wrapper for ``_tmppath_factory.getbasetemp``.""" return legacy_path(self._tmppath_factory.getbasetemp().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 reportinfo(self): assert self.dtest is not None return legacy_path(self.path), self.dtest.lineno, "[doctest] %s" % self.name
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 fspath(self) -> LEGACY_PATH: """(deprecated) returns a legacy_path copy of self.path""" return legacy_path(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 legacy_path(self.path)
def reportinfo(self) -> Tuple[Union[LEGACY_PATH, str], Optional[int], str]: # TODO: enable Path objects in reportinfo return legacy_path(self.path), None, ""
def test_parse_known_args(self, parser: parseopt.Parser) -> None: parser.parse_known_args([legacy_path(".")]) parser.addoption("--hello", action="store_true") ns = parser.parse_known_args(["x", "--y", "--hello", "this"]) assert ns.hello assert ns.file_or_dir == ["x"]