Merge pull request #8174 from bluetech/py-to-pathlib-5
More py.path -> pathlib conversions
This commit is contained in:
		
						commit
						d8d2df7e6f
					
				|  | @ -0,0 +1,6 @@ | ||||||
|  | The following changes have been made to internal pytest types/functions: | ||||||
|  | 
 | ||||||
|  | - The ``path`` property of ``_pytest.code.Code`` returns ``Path`` instead of ``py.path.local``. | ||||||
|  | - The ``path`` property of ``_pytest.code.TracebackEntry`` returns ``Path`` instead of ``py.path.local``. | ||||||
|  | - The ``_pytest.code.getfslineno()`` function returns ``Path`` instead of ``py.path.local``. | ||||||
|  | - The ``_pytest.python.path_matches_patterns()`` function takes ``Path`` instead of ``py.path.local``. | ||||||
|  | @ -43,6 +43,8 @@ from _pytest._io.saferepr import safeformat | ||||||
| from _pytest._io.saferepr import saferepr | from _pytest._io.saferepr import saferepr | ||||||
| from _pytest.compat import final | from _pytest.compat import final | ||||||
| from _pytest.compat import get_real_func | from _pytest.compat import get_real_func | ||||||
|  | from _pytest.pathlib import absolutepath | ||||||
|  | from _pytest.pathlib import bestrelpath | ||||||
| 
 | 
 | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|     from typing_extensions import Literal |     from typing_extensions import Literal | ||||||
|  | @ -78,16 +80,16 @@ class Code: | ||||||
|         return self.raw.co_name |         return self.raw.co_name | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def path(self) -> Union[py.path.local, str]: |     def path(self) -> Union[Path, str]: | ||||||
|         """Return a path object pointing to source code, or an ``str`` in |         """Return a path object pointing to source code, or an ``str`` in | ||||||
|         case of ``OSError`` / non-existing file.""" |         case of ``OSError`` / non-existing file.""" | ||||||
|         if not self.raw.co_filename: |         if not self.raw.co_filename: | ||||||
|             return "" |             return "" | ||||||
|         try: |         try: | ||||||
|             p = py.path.local(self.raw.co_filename) |             p = absolutepath(self.raw.co_filename) | ||||||
|             # maybe don't try this checking |             # maybe don't try this checking | ||||||
|             if not p.check(): |             if not p.exists(): | ||||||
|                 raise OSError("py.path check failed.") |                 raise OSError("path check failed.") | ||||||
|             return p |             return p | ||||||
|         except OSError: |         except OSError: | ||||||
|             # XXX maybe try harder like the weird logic |             # XXX maybe try harder like the weird logic | ||||||
|  | @ -223,7 +225,7 @@ class TracebackEntry: | ||||||
|         return source.getstatement(self.lineno) |         return source.getstatement(self.lineno) | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def path(self) -> Union[py.path.local, str]: |     def path(self) -> Union[Path, str]: | ||||||
|         """Path to the source code.""" |         """Path to the source code.""" | ||||||
|         return self.frame.code.path |         return self.frame.code.path | ||||||
| 
 | 
 | ||||||
|  | @ -336,10 +338,10 @@ class Traceback(List[TracebackEntry]): | ||||||
| 
 | 
 | ||||||
|     def cut( |     def cut( | ||||||
|         self, |         self, | ||||||
|         path=None, |         path: Optional[Union[Path, str]] = None, | ||||||
|         lineno: Optional[int] = None, |         lineno: Optional[int] = None, | ||||||
|         firstlineno: Optional[int] = None, |         firstlineno: Optional[int] = None, | ||||||
|         excludepath: Optional[py.path.local] = None, |         excludepath: Optional[Path] = None, | ||||||
|     ) -> "Traceback": |     ) -> "Traceback": | ||||||
|         """Return a Traceback instance wrapping part of this Traceback. |         """Return a Traceback instance wrapping part of this Traceback. | ||||||
| 
 | 
 | ||||||
|  | @ -353,16 +355,18 @@ class Traceback(List[TracebackEntry]): | ||||||
|         for x in self: |         for x in self: | ||||||
|             code = x.frame.code |             code = x.frame.code | ||||||
|             codepath = code.path |             codepath = code.path | ||||||
|  |             if path is not None and codepath != path: | ||||||
|  |                 continue | ||||||
|             if ( |             if ( | ||||||
|                 (path is None or codepath == path) |                 excludepath is not None | ||||||
|                 and ( |                 and isinstance(codepath, Path) | ||||||
|                     excludepath is None |                 and excludepath in codepath.parents | ||||||
|                     or not isinstance(codepath, py.path.local) |  | ||||||
|                     or not codepath.relto(excludepath) |  | ||||||
|                 ) |  | ||||||
|                 and (lineno is None or x.lineno == lineno) |  | ||||||
|                 and (firstlineno is None or x.frame.code.firstlineno == firstlineno) |  | ||||||
|             ): |             ): | ||||||
|  |                 continue | ||||||
|  |             if lineno is not None and x.lineno != lineno: | ||||||
|  |                 continue | ||||||
|  |             if firstlineno is not None and x.frame.code.firstlineno != firstlineno: | ||||||
|  |                 continue | ||||||
|             return Traceback(x._rawentry, self._excinfo) |             return Traceback(x._rawentry, self._excinfo) | ||||||
|         return self |         return self | ||||||
| 
 | 
 | ||||||
|  | @ -801,7 +805,8 @@ class FormattedExcinfo: | ||||||
|                 message = "in %s" % (entry.name) |                 message = "in %s" % (entry.name) | ||||||
|             else: |             else: | ||||||
|                 message = excinfo and excinfo.typename or "" |                 message = excinfo and excinfo.typename or "" | ||||||
|             path = self._makepath(entry.path) |             entry_path = entry.path | ||||||
|  |             path = self._makepath(entry_path) | ||||||
|             reprfileloc = ReprFileLocation(path, entry.lineno + 1, message) |             reprfileloc = ReprFileLocation(path, entry.lineno + 1, message) | ||||||
|             localsrepr = self.repr_locals(entry.locals) |             localsrepr = self.repr_locals(entry.locals) | ||||||
|             return ReprEntry(lines, reprargs, localsrepr, reprfileloc, style) |             return ReprEntry(lines, reprargs, localsrepr, reprfileloc, style) | ||||||
|  | @ -814,15 +819,15 @@ class FormattedExcinfo: | ||||||
|                 lines.extend(self.get_exconly(excinfo, indent=4)) |                 lines.extend(self.get_exconly(excinfo, indent=4)) | ||||||
|             return ReprEntry(lines, None, None, None, style) |             return ReprEntry(lines, None, None, None, style) | ||||||
| 
 | 
 | ||||||
|     def _makepath(self, path): |     def _makepath(self, path: Union[Path, str]) -> str: | ||||||
|         if not self.abspath: |         if not self.abspath and isinstance(path, Path): | ||||||
|             try: |             try: | ||||||
|                 np = py.path.local().bestrelpath(path) |                 np = bestrelpath(Path.cwd(), path) | ||||||
|             except OSError: |             except OSError: | ||||||
|                 return path |                 return str(path) | ||||||
|             if len(np) < len(str(path)): |             if len(np) < len(str(path)): | ||||||
|                 path = np |                 return np | ||||||
|         return path |         return str(path) | ||||||
| 
 | 
 | ||||||
|     def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback": |     def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback": | ||||||
|         traceback = excinfo.traceback |         traceback = excinfo.traceback | ||||||
|  | @ -1181,7 +1186,7 @@ class ReprFuncArgs(TerminalRepr): | ||||||
|             tw.line("") |             tw.line("") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def getfslineno(obj: object) -> Tuple[Union[str, py.path.local], int]: | def getfslineno(obj: object) -> Tuple[Union[str, Path], int]: | ||||||
|     """Return source location (path, lineno) for the given object. |     """Return source location (path, lineno) for the given object. | ||||||
| 
 | 
 | ||||||
|     If the source cannot be determined return ("", -1). |     If the source cannot be determined return ("", -1). | ||||||
|  | @ -1203,7 +1208,7 @@ def getfslineno(obj: object) -> Tuple[Union[str, py.path.local], int]: | ||||||
|         except TypeError: |         except TypeError: | ||||||
|             return "", -1 |             return "", -1 | ||||||
| 
 | 
 | ||||||
|         fspath = fn and py.path.local(fn) or "" |         fspath = fn and absolutepath(fn) or "" | ||||||
|         lineno = -1 |         lineno = -1 | ||||||
|         if fspath: |         if fspath: | ||||||
|             try: |             try: | ||||||
|  |  | ||||||
|  | @ -128,7 +128,7 @@ def filter_traceback_for_conftest_import_failure( | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def main( | def main( | ||||||
|     args: Optional[Union[List[str], py.path.local]] = None, |     args: Optional[Union[List[str], "os.PathLike[str]"]] = None, | ||||||
|     plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, |     plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, | ||||||
| ) -> Union[int, ExitCode]: | ) -> Union[int, ExitCode]: | ||||||
|     """Perform an in-process test run. |     """Perform an in-process test run. | ||||||
|  | @ -295,13 +295,15 @@ def get_plugin_manager() -> "PytestPluginManager": | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _prepareconfig( | def _prepareconfig( | ||||||
|     args: Optional[Union[py.path.local, List[str]]] = None, |     args: Optional[Union[List[str], "os.PathLike[str]"]] = None, | ||||||
|     plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, |     plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, | ||||||
| ) -> "Config": | ) -> "Config": | ||||||
|     if args is None: |     if args is None: | ||||||
|         args = sys.argv[1:] |         args = sys.argv[1:] | ||||||
|     elif isinstance(args, py.path.local): |     # TODO: Remove type-ignore after next mypy release. | ||||||
|         args = [str(args)] |     # https://github.com/python/typeshed/commit/076983eec45e739c68551cb6119fd7d85fd4afa9 | ||||||
|  |     elif isinstance(args, os.PathLike):  # type: ignore[misc] | ||||||
|  |         args = [os.fspath(args)] | ||||||
|     elif not isinstance(args, list): |     elif not isinstance(args, list): | ||||||
|         msg = "`args` parameter expected to be a list of strings, got: {!r} (type: {})" |         msg = "`args` parameter expected to be a list of strings, got: {!r} (type: {})" | ||||||
|         raise TypeError(msg.format(args, type(args))) |         raise TypeError(msg.format(args, type(args))) | ||||||
|  | @ -346,7 +348,7 @@ class PytestPluginManager(PluginManager): | ||||||
|         self._conftestpath2mod: Dict[Path, types.ModuleType] = {} |         self._conftestpath2mod: Dict[Path, types.ModuleType] = {} | ||||||
|         self._confcutdir: Optional[Path] = None |         self._confcutdir: Optional[Path] = None | ||||||
|         self._noconftest = False |         self._noconftest = False | ||||||
|         self._duplicatepaths: Set[py.path.local] = set() |         self._duplicatepaths: Set[Path] = set() | ||||||
| 
 | 
 | ||||||
|         # plugins that were explicitly skipped with pytest.skip |         # plugins that were explicitly skipped with pytest.skip | ||||||
|         # list of (module name, skip reason) |         # list of (module name, skip reason) | ||||||
|  |  | ||||||
|  | @ -36,6 +36,7 @@ from _pytest.config.argparsing import Parser | ||||||
| from _pytest.fixtures import FixtureRequest | from _pytest.fixtures import FixtureRequest | ||||||
| from _pytest.nodes import Collector | from _pytest.nodes import Collector | ||||||
| from _pytest.outcomes import OutcomeException | from _pytest.outcomes import OutcomeException | ||||||
|  | from _pytest.pathlib import fnmatch_ex | ||||||
| from _pytest.pathlib import import_path | from _pytest.pathlib import import_path | ||||||
| from _pytest.python_api import approx | from _pytest.python_api import approx | ||||||
| from _pytest.warning_types import PytestWarning | from _pytest.warning_types import PytestWarning | ||||||
|  | @ -120,32 +121,32 @@ def pytest_unconfigure() -> None: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def pytest_collect_file( | def pytest_collect_file( | ||||||
|     path: py.path.local, parent: Collector, |     fspath: Path, path: py.path.local, parent: Collector, | ||||||
| ) -> Optional[Union["DoctestModule", "DoctestTextfile"]]: | ) -> Optional[Union["DoctestModule", "DoctestTextfile"]]: | ||||||
|     config = parent.config |     config = parent.config | ||||||
|     if path.ext == ".py": |     if fspath.suffix == ".py": | ||||||
|         if config.option.doctestmodules and not _is_setup_py(path): |         if config.option.doctestmodules and not _is_setup_py(fspath): | ||||||
|             mod: DoctestModule = DoctestModule.from_parent(parent, fspath=path) |             mod: DoctestModule = DoctestModule.from_parent(parent, fspath=path) | ||||||
|             return mod |             return mod | ||||||
|     elif _is_doctest(config, path, parent): |     elif _is_doctest(config, fspath, parent): | ||||||
|         txt: DoctestTextfile = DoctestTextfile.from_parent(parent, fspath=path) |         txt: DoctestTextfile = DoctestTextfile.from_parent(parent, fspath=path) | ||||||
|         return txt |         return txt | ||||||
|     return None |     return None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _is_setup_py(path: py.path.local) -> bool: | def _is_setup_py(path: Path) -> bool: | ||||||
|     if path.basename != "setup.py": |     if path.name != "setup.py": | ||||||
|         return False |         return False | ||||||
|     contents = path.read_binary() |     contents = path.read_bytes() | ||||||
|     return b"setuptools" in contents or b"distutils" in contents |     return b"setuptools" in contents or b"distutils" in contents | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _is_doctest(config: Config, path: py.path.local, parent) -> bool: | def _is_doctest(config: Config, path: Path, parent: Collector) -> bool: | ||||||
|     if path.ext in (".txt", ".rst") and parent.session.isinitpath(path): |     if path.suffix in (".txt", ".rst") and parent.session.isinitpath(path): | ||||||
|         return True |         return True | ||||||
|     globs = config.getoption("doctestglob") or ["test*.txt"] |     globs = config.getoption("doctestglob") or ["test*.txt"] | ||||||
|     for glob in globs: |     for glob in globs: | ||||||
|         if path.check(fnmatch=glob): |         if fnmatch_ex(glob, path): | ||||||
|             return True |             return True | ||||||
|     return False |     return False | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ import sys | ||||||
| import warnings | import warnings | ||||||
| from collections import defaultdict | from collections import defaultdict | ||||||
| from collections import deque | from collections import deque | ||||||
|  | from pathlib import Path | ||||||
| from types import TracebackType | from types import TracebackType | ||||||
| from typing import Any | from typing import Any | ||||||
| from typing import Callable | from typing import Callable | ||||||
|  | @ -58,6 +59,7 @@ from _pytest.mark.structures import MarkDecorator | ||||||
| from _pytest.outcomes import fail | from _pytest.outcomes import fail | ||||||
| from _pytest.outcomes import TEST_OUTCOME | from _pytest.outcomes import TEST_OUTCOME | ||||||
| from _pytest.pathlib import absolutepath | from _pytest.pathlib import absolutepath | ||||||
|  | from _pytest.pathlib import bestrelpath | ||||||
| from _pytest.store import StoreKey | from _pytest.store import StoreKey | ||||||
| 
 | 
 | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|  | @ -718,7 +720,11 @@ class FixtureRequest: | ||||||
|         for fixturedef in self._get_fixturestack(): |         for fixturedef in self._get_fixturestack(): | ||||||
|             factory = fixturedef.func |             factory = fixturedef.func | ||||||
|             fs, lineno = getfslineno(factory) |             fs, lineno = getfslineno(factory) | ||||||
|             p = self._pyfuncitem.session.fspath.bestrelpath(fs) |             if isinstance(fs, Path): | ||||||
|  |                 session: Session = self._pyfuncitem.session | ||||||
|  |                 p = bestrelpath(Path(session.fspath), fs) | ||||||
|  |             else: | ||||||
|  |                 p = fs | ||||||
|             args = _format_args(factory) |             args = _format_args(factory) | ||||||
|             lines.append("%s:%d:  def %s%s" % (p, lineno + 1, factory.__name__, args)) |             lines.append("%s:%d:  def %s%s" % (p, lineno + 1, factory.__name__, args)) | ||||||
|         return lines |         return lines | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ from _pytest.fixtures import FixtureManager | ||||||
| from _pytest.outcomes import exit | from _pytest.outcomes import exit | ||||||
| from _pytest.pathlib import absolutepath | from _pytest.pathlib import absolutepath | ||||||
| from _pytest.pathlib import bestrelpath | from _pytest.pathlib import bestrelpath | ||||||
|  | from _pytest.pathlib import fnmatch_ex | ||||||
| from _pytest.pathlib import visit | from _pytest.pathlib import visit | ||||||
| from _pytest.reports import CollectReport | from _pytest.reports import CollectReport | ||||||
| from _pytest.reports import TestReport | from _pytest.reports import TestReport | ||||||
|  | @ -353,11 +354,14 @@ def pytest_runtestloop(session: "Session") -> bool: | ||||||
|     return True |     return True | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _in_venv(path: py.path.local) -> bool: | def _in_venv(path: Path) -> bool: | ||||||
|     """Attempt to detect if ``path`` is the root of a Virtual Environment by |     """Attempt to detect if ``path`` is the root of a Virtual Environment by | ||||||
|     checking for the existence of the appropriate activate script.""" |     checking for the existence of the appropriate activate script.""" | ||||||
|     bindir = path.join("Scripts" if sys.platform.startswith("win") else "bin") |     bindir = path.joinpath("Scripts" if sys.platform.startswith("win") else "bin") | ||||||
|     if not bindir.isdir(): |     try: | ||||||
|  |         if not bindir.is_dir(): | ||||||
|  |             return False | ||||||
|  |     except OSError: | ||||||
|         return False |         return False | ||||||
|     activates = ( |     activates = ( | ||||||
|         "activate", |         "activate", | ||||||
|  | @ -367,33 +371,32 @@ def _in_venv(path: py.path.local) -> bool: | ||||||
|         "Activate.bat", |         "Activate.bat", | ||||||
|         "Activate.ps1", |         "Activate.ps1", | ||||||
|     ) |     ) | ||||||
|     return any([fname.basename in activates for fname in bindir.listdir()]) |     return any(fname.name in activates for fname in bindir.iterdir()) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def pytest_ignore_collect(path: py.path.local, config: Config) -> Optional[bool]: | def pytest_ignore_collect(fspath: Path, config: Config) -> Optional[bool]: | ||||||
|     path_ = Path(path) |     ignore_paths = config._getconftest_pathlist("collect_ignore", path=fspath.parent) | ||||||
|     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(absolutepath(x) for x in excludeopt) |         ignore_paths.extend(absolutepath(x) for x in excludeopt) | ||||||
| 
 | 
 | ||||||
|     if path_ in ignore_paths: |     if fspath in ignore_paths: | ||||||
|         return True |         return True | ||||||
| 
 | 
 | ||||||
|     ignore_globs = config._getconftest_pathlist( |     ignore_globs = config._getconftest_pathlist( | ||||||
|         "collect_ignore_glob", path=path_.parent |         "collect_ignore_glob", path=fspath.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(absolutepath(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(fspath), str(glob)) for glob in ignore_globs): | ||||||
|         return True |         return True | ||||||
| 
 | 
 | ||||||
|     allow_in_venv = config.getoption("collect_in_virtualenv") |     allow_in_venv = config.getoption("collect_in_virtualenv") | ||||||
|     if not allow_in_venv and _in_venv(path): |     if not allow_in_venv and _in_venv(fspath): | ||||||
|         return True |         return True | ||||||
|     return None |     return None | ||||||
| 
 | 
 | ||||||
|  | @ -538,21 +541,21 @@ class Session(nodes.FSCollector): | ||||||
|         if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config): |         if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config): | ||||||
|             return False |             return False | ||||||
|         norecursepatterns = self.config.getini("norecursedirs") |         norecursepatterns = self.config.getini("norecursedirs") | ||||||
|         if any(path.check(fnmatch=pat) for pat in norecursepatterns): |         if any(fnmatch_ex(pat, fspath) for pat in norecursepatterns): | ||||||
|             return False |             return False | ||||||
|         return True |         return True | ||||||
| 
 | 
 | ||||||
|     def _collectfile( |     def _collectfile( | ||||||
|         self, path: py.path.local, handle_dupes: bool = True |         self, fspath: Path, handle_dupes: bool = True | ||||||
|     ) -> Sequence[nodes.Collector]: |     ) -> Sequence[nodes.Collector]: | ||||||
|         fspath = Path(path) |         path = py.path.local(fspath) | ||||||
|         assert ( |         assert ( | ||||||
|             path.isfile() |             fspath.is_file() | ||||||
|         ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( |         ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( | ||||||
|             path, path.isdir(), path.exists(), path.islink() |             fspath, fspath.is_dir(), fspath.exists(), fspath.is_symlink() | ||||||
|         ) |         ) | ||||||
|         ihook = self.gethookproxy(path) |         ihook = self.gethookproxy(fspath) | ||||||
|         if not self.isinitpath(path): |         if not self.isinitpath(fspath): | ||||||
|             if ihook.pytest_ignore_collect( |             if ihook.pytest_ignore_collect( | ||||||
|                 fspath=fspath, path=path, config=self.config |                 fspath=fspath, path=path, config=self.config | ||||||
|             ): |             ): | ||||||
|  | @ -562,10 +565,10 @@ class Session(nodes.FSCollector): | ||||||
|             keepduplicates = self.config.getoption("keepduplicates") |             keepduplicates = self.config.getoption("keepduplicates") | ||||||
|             if not keepduplicates: |             if not keepduplicates: | ||||||
|                 duplicate_paths = self.config.pluginmanager._duplicatepaths |                 duplicate_paths = self.config.pluginmanager._duplicatepaths | ||||||
|                 if path in duplicate_paths: |                 if fspath in duplicate_paths: | ||||||
|                     return () |                     return () | ||||||
|                 else: |                 else: | ||||||
|                     duplicate_paths.add(path) |                     duplicate_paths.add(fspath) | ||||||
| 
 | 
 | ||||||
|         return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self)  # type: ignore[no-any-return] |         return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self)  # type: ignore[no-any-return] | ||||||
| 
 | 
 | ||||||
|  | @ -652,10 +655,8 @@ class Session(nodes.FSCollector): | ||||||
|         from _pytest.python import Package |         from _pytest.python import Package | ||||||
| 
 | 
 | ||||||
|         # Keep track of any collected nodes in here, so we don't duplicate fixtures. |         # Keep track of any collected nodes in here, so we don't duplicate fixtures. | ||||||
|         node_cache1: Dict[py.path.local, Sequence[nodes.Collector]] = {} |         node_cache1: Dict[Path, Sequence[nodes.Collector]] = {} | ||||||
|         node_cache2: Dict[ |         node_cache2: Dict[Tuple[Type[nodes.Collector], Path], nodes.Collector] = ({}) | ||||||
|             Tuple[Type[nodes.Collector], py.path.local], nodes.Collector |  | ||||||
|         ] = ({}) |  | ||||||
| 
 | 
 | ||||||
|         # Keep track of any collected collectors in matchnodes paths, so they |         # Keep track of any collected collectors in matchnodes paths, so they | ||||||
|         # are not collected more than once. |         # are not collected more than once. | ||||||
|  | @ -679,31 +680,31 @@ class Session(nodes.FSCollector): | ||||||
|                         break |                         break | ||||||
| 
 | 
 | ||||||
|                     if parent.is_dir(): |                     if parent.is_dir(): | ||||||
|                         pkginit = py.path.local(parent / "__init__.py") |                         pkginit = parent / "__init__.py" | ||||||
|                         if pkginit.isfile() and pkginit not in node_cache1: |                         if pkginit.is_file() and pkginit not in node_cache1: | ||||||
|                             col = self._collectfile(pkginit, handle_dupes=False) |                             col = self._collectfile(pkginit, handle_dupes=False) | ||||||
|                             if col: |                             if col: | ||||||
|                                 if isinstance(col[0], Package): |                                 if isinstance(col[0], Package): | ||||||
|                                     pkg_roots[str(parent)] = col[0] |                                     pkg_roots[str(parent)] = col[0] | ||||||
|                                 node_cache1[col[0].fspath] = [col[0]] |                                 node_cache1[Path(col[0].fspath)] = [col[0]] | ||||||
| 
 | 
 | ||||||
|             # If it's a directory argument, recurse and look for any Subpackages. |             # If it's a directory argument, recurse and look for any Subpackages. | ||||||
|             # Let the Package collector deal with subnodes, don't collect here. |             # Let the Package collector deal with subnodes, don't collect here. | ||||||
|             if argpath.is_dir(): |             if argpath.is_dir(): | ||||||
|                 assert not names, "invalid arg {!r}".format((argpath, names)) |                 assert not names, "invalid arg {!r}".format((argpath, names)) | ||||||
| 
 | 
 | ||||||
|                 seen_dirs: Set[py.path.local] = set() |                 seen_dirs: Set[Path] = set() | ||||||
|                 for direntry in visit(str(argpath), self._recurse): |                 for direntry in visit(str(argpath), self._recurse): | ||||||
|                     if not direntry.is_file(): |                     if not direntry.is_file(): | ||||||
|                         continue |                         continue | ||||||
| 
 | 
 | ||||||
|                     path = py.path.local(direntry.path) |                     path = Path(direntry.path) | ||||||
|                     dirpath = path.dirpath() |                     dirpath = path.parent | ||||||
| 
 | 
 | ||||||
|                     if dirpath not in seen_dirs: |                     if dirpath not in seen_dirs: | ||||||
|                         # Collect packages first. |                         # Collect packages first. | ||||||
|                         seen_dirs.add(dirpath) |                         seen_dirs.add(dirpath) | ||||||
|                         pkginit = dirpath.join("__init__.py") |                         pkginit = dirpath / "__init__.py" | ||||||
|                         if pkginit.exists(): |                         if pkginit.exists(): | ||||||
|                             for x in self._collectfile(pkginit): |                             for x in self._collectfile(pkginit): | ||||||
|                                 yield x |                                 yield x | ||||||
|  | @ -714,23 +715,22 @@ class Session(nodes.FSCollector): | ||||||
|                         continue |                         continue | ||||||
| 
 | 
 | ||||||
|                     for x in self._collectfile(path): |                     for x in self._collectfile(path): | ||||||
|                         key = (type(x), x.fspath) |                         key2 = (type(x), Path(x.fspath)) | ||||||
|                         if key in node_cache2: |                         if key2 in node_cache2: | ||||||
|                             yield node_cache2[key] |                             yield node_cache2[key2] | ||||||
|                         else: |                         else: | ||||||
|                             node_cache2[key] = x |                             node_cache2[key2] = x | ||||||
|                             yield x |                             yield x | ||||||
|             else: |             else: | ||||||
|                 assert argpath.is_file() |                 assert argpath.is_file() | ||||||
| 
 | 
 | ||||||
|                 argpath_ = py.path.local(argpath) |                 if argpath in node_cache1: | ||||||
|                 if argpath_ in node_cache1: |                     col = node_cache1[argpath] | ||||||
|                     col = node_cache1[argpath_] |  | ||||||
|                 else: |                 else: | ||||||
|                     collect_root = pkg_roots.get(argpath_.dirname, self) |                     collect_root = pkg_roots.get(str(argpath.parent), self) | ||||||
|                     col = collect_root._collectfile(argpath_, handle_dupes=False) |                     col = collect_root._collectfile(argpath, handle_dupes=False) | ||||||
|                     if col: |                     if col: | ||||||
|                         node_cache1[argpath_] = col |                         node_cache1[argpath] = col | ||||||
| 
 | 
 | ||||||
|                 matching = [] |                 matching = [] | ||||||
|                 work: List[ |                 work: List[ | ||||||
|  | @ -846,7 +846,7 @@ def resolve_collection_argument( | ||||||
| 
 | 
 | ||||||
|     This function ensures the path exists, and returns a tuple: |     This function ensures the path exists, and returns a tuple: | ||||||
| 
 | 
 | ||||||
|         (py.path.path("/full/path/to/pkg/tests/test_foo.py"), ["TestClass", "test_foo"]) |         (Path("/full/path/to/pkg/tests/test_foo.py"), ["TestClass", "test_foo"]) | ||||||
| 
 | 
 | ||||||
|     When as_pypath is True, expects that the command-line argument actually contains |     When as_pypath is True, expects that the command-line argument actually contains | ||||||
|     module paths instead of file-system paths: |     module paths instead of file-system paths: | ||||||
|  |  | ||||||
|  | @ -39,7 +39,7 @@ if TYPE_CHECKING: | ||||||
| 
 | 
 | ||||||
| SEP = "/" | SEP = "/" | ||||||
| 
 | 
 | ||||||
| tracebackcutdir = py.path.local(_pytest.__file__).dirpath() | tracebackcutdir = Path(_pytest.__file__).parent | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def iterparentnodeids(nodeid: str) -> Iterator[str]: | def iterparentnodeids(nodeid: str) -> Iterator[str]: | ||||||
|  | @ -416,9 +416,7 @@ class Node(metaclass=NodeMeta): | ||||||
|         return self._repr_failure_py(excinfo, style) |         return self._repr_failure_py(excinfo, style) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_fslocation_from_item( | def get_fslocation_from_item(node: "Node") -> Tuple[Union[str, Path], Optional[int]]: | ||||||
|     node: "Node", |  | ||||||
| ) -> Tuple[Union[str, py.path.local], Optional[int]]: |  | ||||||
|     """Try to extract the actual location from a node, depending on available attributes: |     """Try to extract the actual location from a node, depending on available attributes: | ||||||
| 
 | 
 | ||||||
|     * "location": a pair (path, lineno) |     * "location": a pair (path, lineno) | ||||||
|  | @ -474,7 +472,7 @@ class Collector(Node): | ||||||
|     def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None: |     def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None: | ||||||
|         if hasattr(self, "fspath"): |         if hasattr(self, "fspath"): | ||||||
|             traceback = excinfo.traceback |             traceback = excinfo.traceback | ||||||
|             ntraceback = traceback.cut(path=self.fspath) |             ntraceback = traceback.cut(path=Path(self.fspath)) | ||||||
|             if ntraceback == traceback: |             if ntraceback == traceback: | ||||||
|                 ntraceback = ntraceback.cut(excludepath=tracebackcutdir) |                 ntraceback = ntraceback.cut(excludepath=tracebackcutdir) | ||||||
|             excinfo.traceback = ntraceback.filter() |             excinfo.traceback = ntraceback.filter() | ||||||
|  |  | ||||||
|  | @ -387,7 +387,7 @@ def resolve_from_str(input: str, rootpath: Path) -> Path: | ||||||
|         return rootpath.joinpath(input) |         return rootpath.joinpath(input) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def fnmatch_ex(pattern: str, path) -> bool: | def fnmatch_ex(pattern: str, path: Union[str, "os.PathLike[str]"]) -> bool: | ||||||
|     """A port of FNMatcher from py.path.common which works with PurePath() instances. |     """A port of FNMatcher from py.path.common which works with PurePath() instances. | ||||||
| 
 | 
 | ||||||
|     The difference between this algorithm and PurePath.match() is that the |     The difference between this algorithm and PurePath.match() is that the | ||||||
|  |  | ||||||
|  | @ -66,6 +66,8 @@ from _pytest.mark.structures import MarkDecorator | ||||||
| from _pytest.mark.structures import normalize_mark_list | from _pytest.mark.structures import normalize_mark_list | ||||||
| from _pytest.outcomes import fail | from _pytest.outcomes import fail | ||||||
| from _pytest.outcomes import skip | from _pytest.outcomes import skip | ||||||
|  | from _pytest.pathlib import bestrelpath | ||||||
|  | from _pytest.pathlib import fnmatch_ex | ||||||
| from _pytest.pathlib import import_path | from _pytest.pathlib import import_path | ||||||
| from _pytest.pathlib import ImportPathMismatchError | from _pytest.pathlib import ImportPathMismatchError | ||||||
| from _pytest.pathlib import parts | from _pytest.pathlib import parts | ||||||
|  | @ -190,11 +192,10 @@ def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]: | ||||||
| def pytest_collect_file( | def pytest_collect_file( | ||||||
|     fspath: Path, path: py.path.local, parent: nodes.Collector |     fspath: Path, path: py.path.local, parent: nodes.Collector | ||||||
| ) -> Optional["Module"]: | ) -> Optional["Module"]: | ||||||
|     ext = path.ext |     if fspath.suffix == ".py": | ||||||
|     if ext == ".py": |  | ||||||
|         if not parent.session.isinitpath(fspath): |         if not parent.session.isinitpath(fspath): | ||||||
|             if not path_matches_patterns( |             if not path_matches_patterns( | ||||||
|                 path, parent.config.getini("python_files") + ["__init__.py"] |                 fspath, parent.config.getini("python_files") + ["__init__.py"] | ||||||
|             ): |             ): | ||||||
|                 return None |                 return None | ||||||
|         ihook = parent.session.gethookproxy(fspath) |         ihook = parent.session.gethookproxy(fspath) | ||||||
|  | @ -205,13 +206,13 @@ def pytest_collect_file( | ||||||
|     return None |     return None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def path_matches_patterns(path: py.path.local, patterns: Iterable[str]) -> bool: | def path_matches_patterns(path: Path, patterns: Iterable[str]) -> bool: | ||||||
|     """Return whether path matches any of the patterns in the list of globs given.""" |     """Return whether path matches any of the patterns in the list of globs given.""" | ||||||
|     return any(path.fnmatch(pattern) for pattern in patterns) |     return any(fnmatch_ex(pattern, path) for pattern in patterns) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def pytest_pycollect_makemodule(path: py.path.local, parent) -> "Module": | def pytest_pycollect_makemodule(fspath: Path, path: py.path.local, parent) -> "Module": | ||||||
|     if path.basename == "__init__.py": |     if fspath.name == "__init__.py": | ||||||
|         pkg: Package = Package.from_parent(parent, fspath=path) |         pkg: Package = Package.from_parent(parent, fspath=path) | ||||||
|         return pkg |         return pkg | ||||||
|     mod: Module = Module.from_parent(parent, fspath=path) |     mod: Module = Module.from_parent(parent, fspath=path) | ||||||
|  | @ -340,7 +341,11 @@ class PyobjMixin: | ||||||
|             fspath: Union[py.path.local, str] = file_path |             fspath: Union[py.path.local, str] = file_path | ||||||
|             lineno = compat_co_firstlineno |             lineno = compat_co_firstlineno | ||||||
|         else: |         else: | ||||||
|             fspath, lineno = getfslineno(obj) |             path, lineno = getfslineno(obj) | ||||||
|  |             if isinstance(path, Path): | ||||||
|  |                 fspath = py.path.local(path) | ||||||
|  |             else: | ||||||
|  |                 fspath = path | ||||||
|         modpath = self.getmodpath() |         modpath = self.getmodpath() | ||||||
|         assert isinstance(lineno, int) |         assert isinstance(lineno, int) | ||||||
|         return fspath, lineno, modpath |         return fspath, lineno, modpath | ||||||
|  | @ -673,21 +678,21 @@ class Package(Module): | ||||||
|         if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config): |         if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config): | ||||||
|             return False |             return False | ||||||
|         norecursepatterns = self.config.getini("norecursedirs") |         norecursepatterns = self.config.getini("norecursedirs") | ||||||
|         if any(path.check(fnmatch=pat) for pat in norecursepatterns): |         if any(fnmatch_ex(pat, fspath) for pat in norecursepatterns): | ||||||
|             return False |             return False | ||||||
|         return True |         return True | ||||||
| 
 | 
 | ||||||
|     def _collectfile( |     def _collectfile( | ||||||
|         self, path: py.path.local, handle_dupes: bool = True |         self, fspath: Path, handle_dupes: bool = True | ||||||
|     ) -> Sequence[nodes.Collector]: |     ) -> Sequence[nodes.Collector]: | ||||||
|         fspath = Path(path) |         path = py.path.local(fspath) | ||||||
|         assert ( |         assert ( | ||||||
|             path.isfile() |             fspath.is_file() | ||||||
|         ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( |         ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( | ||||||
|             path, path.isdir(), path.exists(), path.islink() |             path, fspath.is_dir(), fspath.exists(), fspath.is_symlink() | ||||||
|         ) |         ) | ||||||
|         ihook = self.session.gethookproxy(path) |         ihook = self.session.gethookproxy(fspath) | ||||||
|         if not self.session.isinitpath(path): |         if not self.session.isinitpath(fspath): | ||||||
|             if ihook.pytest_ignore_collect( |             if ihook.pytest_ignore_collect( | ||||||
|                 fspath=fspath, path=path, config=self.config |                 fspath=fspath, path=path, config=self.config | ||||||
|             ): |             ): | ||||||
|  | @ -697,32 +702,32 @@ class Package(Module): | ||||||
|             keepduplicates = self.config.getoption("keepduplicates") |             keepduplicates = self.config.getoption("keepduplicates") | ||||||
|             if not keepduplicates: |             if not keepduplicates: | ||||||
|                 duplicate_paths = self.config.pluginmanager._duplicatepaths |                 duplicate_paths = self.config.pluginmanager._duplicatepaths | ||||||
|                 if path in duplicate_paths: |                 if fspath in duplicate_paths: | ||||||
|                     return () |                     return () | ||||||
|                 else: |                 else: | ||||||
|                     duplicate_paths.add(path) |                     duplicate_paths.add(fspath) | ||||||
| 
 | 
 | ||||||
|         return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self)  # type: ignore[no-any-return] |         return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self)  # type: ignore[no-any-return] | ||||||
| 
 | 
 | ||||||
|     def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: |     def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: | ||||||
|         this_path = self.fspath.dirpath() |         this_path = Path(self.fspath).parent | ||||||
|         init_module = this_path.join("__init__.py") |         init_module = this_path / "__init__.py" | ||||||
|         if init_module.check(file=1) and path_matches_patterns( |         if init_module.is_file() and path_matches_patterns( | ||||||
|             init_module, self.config.getini("python_files") |             init_module, self.config.getini("python_files") | ||||||
|         ): |         ): | ||||||
|             yield Module.from_parent(self, fspath=init_module) |             yield Module.from_parent(self, fspath=py.path.local(init_module)) | ||||||
|         pkg_prefixes: Set[py.path.local] = set() |         pkg_prefixes: Set[Path] = set() | ||||||
|         for direntry in visit(str(this_path), recurse=self._recurse): |         for direntry in visit(str(this_path), recurse=self._recurse): | ||||||
|             path = py.path.local(direntry.path) |             path = Path(direntry.path) | ||||||
| 
 | 
 | ||||||
|             # We will visit our own __init__.py file, in which case we skip it. |             # We will visit our own __init__.py file, in which case we skip it. | ||||||
|             if direntry.is_file(): |             if direntry.is_file(): | ||||||
|                 if direntry.name == "__init__.py" and path.dirpath() == this_path: |                 if direntry.name == "__init__.py" and path.parent == this_path: | ||||||
|                     continue |                     continue | ||||||
| 
 | 
 | ||||||
|             parts_ = parts(direntry.path) |             parts_ = parts(direntry.path) | ||||||
|             if any( |             if any( | ||||||
|                 str(pkg_prefix) in parts_ and pkg_prefix.join("__init__.py") != path |                 str(pkg_prefix) in parts_ and pkg_prefix / "__init__.py" != path | ||||||
|                 for pkg_prefix in pkg_prefixes |                 for pkg_prefix in pkg_prefixes | ||||||
|             ): |             ): | ||||||
|                 continue |                 continue | ||||||
|  | @ -732,7 +737,7 @@ class Package(Module): | ||||||
|             elif not direntry.is_dir(): |             elif not direntry.is_dir(): | ||||||
|                 # Broken symlink or invalid/missing file. |                 # Broken symlink or invalid/missing file. | ||||||
|                 continue |                 continue | ||||||
|             elif path.join("__init__.py").check(file=1): |             elif path.joinpath("__init__.py").is_file(): | ||||||
|                 pkg_prefixes.add(path) |                 pkg_prefixes.add(path) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1412,13 +1417,13 @@ def _show_fixtures_per_test(config: Config, session: Session) -> None: | ||||||
|     import _pytest.config |     import _pytest.config | ||||||
| 
 | 
 | ||||||
|     session.perform_collect() |     session.perform_collect() | ||||||
|     curdir = py.path.local() |     curdir = Path.cwd() | ||||||
|     tw = _pytest.config.create_terminal_writer(config) |     tw = _pytest.config.create_terminal_writer(config) | ||||||
|     verbose = config.getvalue("verbose") |     verbose = config.getvalue("verbose") | ||||||
| 
 | 
 | ||||||
|     def get_best_relpath(func): |     def get_best_relpath(func) -> str: | ||||||
|         loc = getlocation(func, str(curdir)) |         loc = getlocation(func, str(curdir)) | ||||||
|         return curdir.bestrelpath(py.path.local(loc)) |         return bestrelpath(curdir, Path(loc)) | ||||||
| 
 | 
 | ||||||
|     def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None: |     def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None: | ||||||
|         argname = fixture_def.argname |         argname = fixture_def.argname | ||||||
|  | @ -1468,7 +1473,7 @@ def _showfixtures_main(config: Config, session: Session) -> None: | ||||||
|     import _pytest.config |     import _pytest.config | ||||||
| 
 | 
 | ||||||
|     session.perform_collect() |     session.perform_collect() | ||||||
|     curdir = py.path.local() |     curdir = Path.cwd() | ||||||
|     tw = _pytest.config.create_terminal_writer(config) |     tw = _pytest.config.create_terminal_writer(config) | ||||||
|     verbose = config.getvalue("verbose") |     verbose = config.getvalue("verbose") | ||||||
| 
 | 
 | ||||||
|  | @ -1490,7 +1495,7 @@ def _showfixtures_main(config: Config, session: Session) -> None: | ||||||
|                 ( |                 ( | ||||||
|                     len(fixturedef.baseid), |                     len(fixturedef.baseid), | ||||||
|                     fixturedef.func.__module__, |                     fixturedef.func.__module__, | ||||||
|                     curdir.bestrelpath(py.path.local(loc)), |                     bestrelpath(curdir, Path(loc)), | ||||||
|                     fixturedef.argname, |                     fixturedef.argname, | ||||||
|                     fixturedef, |                     fixturedef, | ||||||
|                 ) |                 ) | ||||||
|  |  | ||||||
|  | @ -285,15 +285,13 @@ class WarningReport: | ||||||
|         User friendly message about the warning. |         User friendly message about the warning. | ||||||
|     :ivar str|None nodeid: |     :ivar str|None nodeid: | ||||||
|         nodeid that generated the warning (see ``get_location``). |         nodeid that generated the warning (see ``get_location``). | ||||||
|     :ivar tuple|py.path.local fslocation: |     :ivar tuple fslocation: | ||||||
|         File system location of the source of the warning (see ``get_location``). |         File system location of the source of the warning (see ``get_location``). | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     message = attr.ib(type=str) |     message = attr.ib(type=str) | ||||||
|     nodeid = attr.ib(type=Optional[str], default=None) |     nodeid = attr.ib(type=Optional[str], default=None) | ||||||
|     fslocation = attr.ib( |     fslocation = attr.ib(type=Optional[Tuple[str, int]], default=None) | ||||||
|         type=Optional[Union[Tuple[str, int], py.path.local]], default=None |  | ||||||
|     ) |  | ||||||
|     count_towards_summary = True |     count_towards_summary = True | ||||||
| 
 | 
 | ||||||
|     def get_location(self, config: Config) -> Optional[str]: |     def get_location(self, config: Config) -> Optional[str]: | ||||||
|  | @ -301,14 +299,9 @@ class WarningReport: | ||||||
|         if self.nodeid: |         if self.nodeid: | ||||||
|             return self.nodeid |             return self.nodeid | ||||||
|         if self.fslocation: |         if self.fslocation: | ||||||
|             if isinstance(self.fslocation, tuple) and len(self.fslocation) >= 2: |             filename, linenum = self.fslocation | ||||||
|                 filename, linenum = self.fslocation[:2] |             relpath = bestrelpath(config.invocation_params.dir, absolutepath(filename)) | ||||||
|                 relpath = bestrelpath( |  | ||||||
|                     config.invocation_params.dir, absolutepath(filename) |  | ||||||
|                 ) |  | ||||||
|             return f"{relpath}:{linenum}" |             return f"{relpath}:{linenum}" | ||||||
|             else: |  | ||||||
|                 return str(self.fslocation) |  | ||||||
|         return None |         return None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import importlib | import importlib | ||||||
| import io | import io | ||||||
| import operator | import operator | ||||||
| import os |  | ||||||
| import queue | import queue | ||||||
| import sys | import sys | ||||||
| import textwrap | import textwrap | ||||||
|  | @ -12,14 +11,14 @@ from typing import Tuple | ||||||
| from typing import TYPE_CHECKING | from typing import TYPE_CHECKING | ||||||
| from typing import Union | from typing import Union | ||||||
| 
 | 
 | ||||||
| import py |  | ||||||
| 
 |  | ||||||
| import _pytest | import _pytest | ||||||
| import pytest | import pytest | ||||||
| from _pytest._code.code import ExceptionChainRepr | from _pytest._code.code import ExceptionChainRepr | ||||||
| from _pytest._code.code import ExceptionInfo | from _pytest._code.code import ExceptionInfo | ||||||
| from _pytest._code.code import FormattedExcinfo | from _pytest._code.code import FormattedExcinfo | ||||||
| from _pytest._io import TerminalWriter | from _pytest._io import TerminalWriter | ||||||
|  | from _pytest.monkeypatch import MonkeyPatch | ||||||
|  | from _pytest.pathlib import bestrelpath | ||||||
| from _pytest.pathlib import import_path | from _pytest.pathlib import import_path | ||||||
| from _pytest.pytester import LineMatcher | from _pytest.pytester import LineMatcher | ||||||
| from _pytest.pytester import Pytester | from _pytest.pytester import Pytester | ||||||
|  | @ -150,9 +149,10 @@ class TestTraceback_f_g_h: | ||||||
|             "    except somenoname:  # type: ignore[name-defined] # noqa: F821", |             "    except somenoname:  # type: ignore[name-defined] # noqa: F821", | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
|     def test_traceback_cut(self): |     def test_traceback_cut(self) -> None: | ||||||
|         co = _pytest._code.Code.from_function(f) |         co = _pytest._code.Code.from_function(f) | ||||||
|         path, firstlineno = co.path, co.firstlineno |         path, firstlineno = co.path, co.firstlineno | ||||||
|  |         assert isinstance(path, Path) | ||||||
|         traceback = self.excinfo.traceback |         traceback = self.excinfo.traceback | ||||||
|         newtraceback = traceback.cut(path=path, firstlineno=firstlineno) |         newtraceback = traceback.cut(path=path, firstlineno=firstlineno) | ||||||
|         assert len(newtraceback) == 1 |         assert len(newtraceback) == 1 | ||||||
|  | @ -163,11 +163,11 @@ class TestTraceback_f_g_h: | ||||||
|         p = pytester.makepyfile("def f(): raise ValueError") |         p = pytester.makepyfile("def f(): raise ValueError") | ||||||
|         with pytest.raises(ValueError) as excinfo: |         with pytest.raises(ValueError) as excinfo: | ||||||
|             import_path(p).f()  # type: ignore[attr-defined] |             import_path(p).f()  # type: ignore[attr-defined] | ||||||
|         basedir = py.path.local(pytest.__file__).dirpath() |         basedir = Path(pytest.__file__).parent | ||||||
|         newtraceback = excinfo.traceback.cut(excludepath=basedir) |         newtraceback = excinfo.traceback.cut(excludepath=basedir) | ||||||
|         for x in newtraceback: |         for x in newtraceback: | ||||||
|             if hasattr(x, "path"): |             assert isinstance(x.path, Path) | ||||||
|                 assert not py.path.local(x.path).relto(basedir) |             assert basedir not in x.path.parents | ||||||
|         assert newtraceback[-1].frame.code.path == p |         assert newtraceback[-1].frame.code.path == p | ||||||
| 
 | 
 | ||||||
|     def test_traceback_filter(self): |     def test_traceback_filter(self): | ||||||
|  | @ -376,7 +376,7 @@ def test_excinfo_no_python_sourcecode(tmpdir): | ||||||
|     for item in excinfo.traceback: |     for item in excinfo.traceback: | ||||||
|         print(item)  # XXX: for some reason jinja.Template.render is printed in full |         print(item)  # XXX: for some reason jinja.Template.render is printed in full | ||||||
|         item.source  # shouldn't fail |         item.source  # shouldn't fail | ||||||
|         if isinstance(item.path, py.path.local) and item.path.basename == "test.txt": |         if isinstance(item.path, Path) and item.path.name == "test.txt": | ||||||
|             assert str(item.source) == "{{ h()}}:" |             assert str(item.source) == "{{ h()}}:" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -392,16 +392,16 @@ def test_entrysource_Queue_example(): | ||||||
|     assert s.startswith("def get") |     assert s.startswith("def get") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_codepath_Queue_example(): | def test_codepath_Queue_example() -> None: | ||||||
|     try: |     try: | ||||||
|         queue.Queue().get(timeout=0.001) |         queue.Queue().get(timeout=0.001) | ||||||
|     except queue.Empty: |     except queue.Empty: | ||||||
|         excinfo = _pytest._code.ExceptionInfo.from_current() |         excinfo = _pytest._code.ExceptionInfo.from_current() | ||||||
|     entry = excinfo.traceback[-1] |     entry = excinfo.traceback[-1] | ||||||
|     path = entry.path |     path = entry.path | ||||||
|     assert isinstance(path, py.path.local) |     assert isinstance(path, Path) | ||||||
|     assert path.basename.lower() == "queue.py" |     assert path.name.lower() == "queue.py" | ||||||
|     assert path.check() |     assert path.exists() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_match_succeeds(): | def test_match_succeeds(): | ||||||
|  | @ -805,21 +805,21 @@ raise ValueError() | ||||||
| 
 | 
 | ||||||
|         raised = 0 |         raised = 0 | ||||||
| 
 | 
 | ||||||
|         orig_getcwd = os.getcwd |         orig_path_cwd = Path.cwd | ||||||
| 
 | 
 | ||||||
|         def raiseos(): |         def raiseos(): | ||||||
|             nonlocal raised |             nonlocal raised | ||||||
|             upframe = sys._getframe().f_back |             upframe = sys._getframe().f_back | ||||||
|             assert upframe is not None |             assert upframe is not None | ||||||
|             if upframe.f_code.co_name == "checked_call": |             if upframe.f_code.co_name == "_makepath": | ||||||
|                 # Only raise with expected calls, but not via e.g. inspect for |                 # Only raise with expected calls, but not via e.g. inspect for | ||||||
|                 # py38-windows. |                 # py38-windows. | ||||||
|                 raised += 1 |                 raised += 1 | ||||||
|                 raise OSError(2, "custom_oserror") |                 raise OSError(2, "custom_oserror") | ||||||
|             return orig_getcwd() |             return orig_path_cwd() | ||||||
| 
 | 
 | ||||||
|         monkeypatch.setattr(os, "getcwd", raiseos) |         monkeypatch.setattr(Path, "cwd", raiseos) | ||||||
|         assert p._makepath(__file__) == __file__ |         assert p._makepath(Path(__file__)) == __file__ | ||||||
|         assert raised == 1 |         assert raised == 1 | ||||||
|         repr_tb = p.repr_traceback(excinfo) |         repr_tb = p.repr_traceback(excinfo) | ||||||
| 
 | 
 | ||||||
|  | @ -1015,7 +1015,9 @@ raise ValueError() | ||||||
|         assert line.endswith("mod.py") |         assert line.endswith("mod.py") | ||||||
|         assert tw_mock.lines[10] == ":3: ValueError" |         assert tw_mock.lines[10] == ":3: ValueError" | ||||||
| 
 | 
 | ||||||
|     def test_toterminal_long_filenames(self, importasmod, tw_mock): |     def test_toterminal_long_filenames( | ||||||
|  |         self, importasmod, tw_mock, monkeypatch: MonkeyPatch | ||||||
|  |     ) -> None: | ||||||
|         mod = importasmod( |         mod = importasmod( | ||||||
|             """ |             """ | ||||||
|             def f(): |             def f(): | ||||||
|  | @ -1023,12 +1025,11 @@ raise ValueError() | ||||||
|         """ |         """ | ||||||
|         ) |         ) | ||||||
|         excinfo = pytest.raises(ValueError, mod.f) |         excinfo = pytest.raises(ValueError, mod.f) | ||||||
|         path = py.path.local(mod.__file__) |         path = Path(mod.__file__) | ||||||
|         old = path.dirpath().chdir() |         monkeypatch.chdir(path.parent) | ||||||
|         try: |  | ||||||
|         repr = excinfo.getrepr(abspath=False) |         repr = excinfo.getrepr(abspath=False) | ||||||
|         repr.toterminal(tw_mock) |         repr.toterminal(tw_mock) | ||||||
|             x = py.path.local().bestrelpath(path) |         x = bestrelpath(Path.cwd(), path) | ||||||
|         if len(x) < len(str(path)): |         if len(x) < len(str(path)): | ||||||
|             msg = tw_mock.get_write_msg(-2) |             msg = tw_mock.get_write_msg(-2) | ||||||
|             assert msg == "mod.py" |             assert msg == "mod.py" | ||||||
|  | @ -1037,11 +1038,9 @@ raise ValueError() | ||||||
|         repr = excinfo.getrepr(abspath=True) |         repr = excinfo.getrepr(abspath=True) | ||||||
|         repr.toterminal(tw_mock) |         repr.toterminal(tw_mock) | ||||||
|         msg = tw_mock.get_write_msg(-2) |         msg = tw_mock.get_write_msg(-2) | ||||||
|             assert msg == path |         assert msg == str(path) | ||||||
|         line = tw_mock.lines[-1] |         line = tw_mock.lines[-1] | ||||||
|         assert line == ":3: ValueError" |         assert line == ":3: ValueError" | ||||||
|         finally: |  | ||||||
|             old.chdir() |  | ||||||
| 
 | 
 | ||||||
|     @pytest.mark.parametrize( |     @pytest.mark.parametrize( | ||||||
|         "reproptions", |         "reproptions", | ||||||
|  |  | ||||||
|  | @ -6,13 +6,12 @@ import inspect | ||||||
| import linecache | import linecache | ||||||
| import sys | import sys | ||||||
| import textwrap | import textwrap | ||||||
|  | from pathlib import Path | ||||||
| from types import CodeType | from types import CodeType | ||||||
| from typing import Any | from typing import Any | ||||||
| from typing import Dict | from typing import Dict | ||||||
| from typing import Optional | from typing import Optional | ||||||
| 
 | 
 | ||||||
| import py.path |  | ||||||
| 
 |  | ||||||
| import pytest | import pytest | ||||||
| from _pytest._code import Code | from _pytest._code import Code | ||||||
| from _pytest._code import Frame | from _pytest._code import Frame | ||||||
|  | @ -352,8 +351,8 @@ def test_getfslineno() -> None: | ||||||
| 
 | 
 | ||||||
|     fspath, lineno = getfslineno(f) |     fspath, lineno = getfslineno(f) | ||||||
| 
 | 
 | ||||||
|     assert isinstance(fspath, py.path.local) |     assert isinstance(fspath, Path) | ||||||
|     assert fspath.basename == "test_source.py" |     assert fspath.name == "test_source.py" | ||||||
|     assert lineno == f.__code__.co_firstlineno - 1  # see findsource |     assert lineno == f.__code__.co_firstlineno - 1  # see findsource | ||||||
| 
 | 
 | ||||||
|     class A: |     class A: | ||||||
|  | @ -362,8 +361,8 @@ def test_getfslineno() -> None: | ||||||
|     fspath, lineno = getfslineno(A) |     fspath, lineno = getfslineno(A) | ||||||
| 
 | 
 | ||||||
|     _, A_lineno = inspect.findsource(A) |     _, A_lineno = inspect.findsource(A) | ||||||
|     assert isinstance(fspath, py.path.local) |     assert isinstance(fspath, Path) | ||||||
|     assert fspath.basename == "test_source.py" |     assert fspath.name == "test_source.py" | ||||||
|     assert lineno == A_lineno |     assert lineno == A_lineno | ||||||
| 
 | 
 | ||||||
|     assert getfslineno(3) == ("", -1) |     assert getfslineno(3) == ("", -1) | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ import pytest | ||||||
| from _pytest.config import ExitCode | from _pytest.config import ExitCode | ||||||
| from _pytest.monkeypatch import MonkeyPatch | from _pytest.monkeypatch import MonkeyPatch | ||||||
| from _pytest.pytester import Pytester | from _pytest.pytester import Pytester | ||||||
|  | from _pytest.tmpdir import TempPathFactory | ||||||
| 
 | 
 | ||||||
| pytest_plugins = ("pytester",) | pytest_plugins = ("pytester",) | ||||||
| 
 | 
 | ||||||
|  | @ -139,9 +140,11 @@ class TestNewAPI: | ||||||
|         pytester.runpytest() |         pytester.runpytest() | ||||||
|         assert pytester.path.joinpath(rel_cache_dir).is_dir() |         assert pytester.path.joinpath(rel_cache_dir).is_dir() | ||||||
| 
 | 
 | ||||||
|     def test_custom_abs_cache_dir(self, pytester: Pytester, tmpdir_factory) -> None: |     def test_custom_abs_cache_dir( | ||||||
|         tmp = str(tmpdir_factory.mktemp("tmp")) |         self, pytester: Pytester, tmp_path_factory: TempPathFactory | ||||||
|         abs_cache_dir = os.path.join(tmp, "custom_cache_dir") |     ) -> None: | ||||||
|  |         tmp = tmp_path_factory.mktemp("tmp") | ||||||
|  |         abs_cache_dir = tmp / "custom_cache_dir" | ||||||
|         pytester.makeini( |         pytester.makeini( | ||||||
|             """ |             """ | ||||||
|             [pytest] |             [pytest] | ||||||
|  | @ -152,7 +155,7 @@ class TestNewAPI: | ||||||
|         ) |         ) | ||||||
|         pytester.makepyfile(test_errored="def test_error():\n    assert False") |         pytester.makepyfile(test_errored="def test_error():\n    assert False") | ||||||
|         pytester.runpytest() |         pytester.runpytest() | ||||||
|         assert Path(abs_cache_dir).is_dir() |         assert abs_cache_dir.is_dir() | ||||||
| 
 | 
 | ||||||
|     def test_custom_cache_dir_with_env_var( |     def test_custom_cache_dir_with_env_var( | ||||||
|         self, pytester: Pytester, monkeypatch: MonkeyPatch |         self, pytester: Pytester, monkeypatch: MonkeyPatch | ||||||
|  | @ -185,9 +188,9 @@ def test_cache_reportheader(env, pytester: Pytester, monkeypatch: MonkeyPatch) - | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_cache_reportheader_external_abspath( | def test_cache_reportheader_external_abspath( | ||||||
|     pytester: Pytester, tmpdir_factory |     pytester: Pytester, tmp_path_factory: TempPathFactory | ||||||
| ) -> None: | ) -> None: | ||||||
|     external_cache = tmpdir_factory.mktemp( |     external_cache = tmp_path_factory.mktemp( | ||||||
|         "test_cache_reportheader_external_abspath_abs" |         "test_cache_reportheader_external_abspath_abs" | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -212,12 +212,12 @@ class TestCollectFS: | ||||||
|         bindir = "Scripts" if sys.platform.startswith("win") else "bin" |         bindir = "Scripts" if sys.platform.startswith("win") else "bin" | ||||||
|         # no bin/activate, not a virtualenv |         # no bin/activate, not a virtualenv | ||||||
|         base_path = pytester.mkdir("venv") |         base_path = pytester.mkdir("venv") | ||||||
|         assert _in_venv(py.path.local(base_path)) is False |         assert _in_venv(base_path) is False | ||||||
|         # with bin/activate, totally a virtualenv |         # with bin/activate, totally a virtualenv | ||||||
|         bin_path = base_path.joinpath(bindir) |         bin_path = base_path.joinpath(bindir) | ||||||
|         bin_path.mkdir() |         bin_path.mkdir() | ||||||
|         bin_path.joinpath(fname).touch() |         bin_path.joinpath(fname).touch() | ||||||
|         assert _in_venv(py.path.local(base_path)) is True |         assert _in_venv(base_path) is True | ||||||
| 
 | 
 | ||||||
|     def test_custom_norecursedirs(self, pytester: Pytester) -> None: |     def test_custom_norecursedirs(self, pytester: Pytester) -> None: | ||||||
|         pytester.makeini( |         pytester.makeini( | ||||||
|  | @ -277,7 +277,7 @@ class TestCollectPluginHookRelay: | ||||||
|                     wascalled.append(path) |                     wascalled.append(path) | ||||||
| 
 | 
 | ||||||
|         pytester.makefile(".abc", "xyz") |         pytester.makefile(".abc", "xyz") | ||||||
|         pytest.main(py.path.local(pytester.path), plugins=[Plugin()]) |         pytest.main(pytester.path, plugins=[Plugin()]) | ||||||
|         assert len(wascalled) == 1 |         assert len(wascalled) == 1 | ||||||
|         assert wascalled[0].ext == ".abc" |         assert wascalled[0].ext == ".abc" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,7 +11,6 @@ from typing import Type | ||||||
| from typing import Union | from typing import Union | ||||||
| 
 | 
 | ||||||
| import attr | import attr | ||||||
| import py.path |  | ||||||
| 
 | 
 | ||||||
| import _pytest._code | import _pytest._code | ||||||
| import pytest | import pytest | ||||||
|  | @ -28,6 +27,7 @@ from _pytest.config.findpaths import determine_setup | ||||||
| from _pytest.config.findpaths import get_common_ancestor | from _pytest.config.findpaths import get_common_ancestor | ||||||
| from _pytest.config.findpaths import locate_config | from _pytest.config.findpaths import locate_config | ||||||
| from _pytest.monkeypatch import MonkeyPatch | from _pytest.monkeypatch import MonkeyPatch | ||||||
|  | from _pytest.pathlib import absolutepath | ||||||
| from _pytest.pytester import Pytester | from _pytest.pytester import Pytester | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -854,8 +854,8 @@ class TestConfigFromdictargs: | ||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         inifile = "../../foo/bar.ini" |         inifilename = "../../foo/bar.ini" | ||||||
|         option_dict = {"inifilename": inifile, "capture": "no"} |         option_dict = {"inifilename": inifilename, "capture": "no"} | ||||||
| 
 | 
 | ||||||
|         cwd = tmp_path.joinpath("a/b") |         cwd = tmp_path.joinpath("a/b") | ||||||
|         cwd.mkdir(parents=True) |         cwd.mkdir(parents=True) | ||||||
|  | @ -873,14 +873,14 @@ class TestConfigFromdictargs: | ||||||
|         with MonkeyPatch.context() as mp: |         with MonkeyPatch.context() as mp: | ||||||
|             mp.chdir(cwd) |             mp.chdir(cwd) | ||||||
|             config = Config.fromdictargs(option_dict, ()) |             config = Config.fromdictargs(option_dict, ()) | ||||||
|             inipath = py.path.local(inifile) |             inipath = absolutepath(inifilename) | ||||||
| 
 | 
 | ||||||
|         assert config.args == [str(cwd)] |         assert config.args == [str(cwd)] | ||||||
|         assert config.option.inifilename == inifile |         assert config.option.inifilename == inifilename | ||||||
|         assert config.option.capture == "no" |         assert config.option.capture == "no" | ||||||
| 
 | 
 | ||||||
|         # this indicates this is the file used for getting configuration values |         # this indicates this is the file used for getting configuration values | ||||||
|         assert config.inifile == inipath |         assert config.inipath == inipath | ||||||
|         assert config.inicfg.get("name") == "value" |         assert config.inicfg.get("name") == "value" | ||||||
|         assert config.inicfg.get("should_not_be_set") is None |         assert config.inicfg.get("should_not_be_set") is None | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import inspect | import inspect | ||||||
| import textwrap | import textwrap | ||||||
|  | from pathlib import Path | ||||||
| from typing import Callable | from typing import Callable | ||||||
| from typing import Optional | from typing import Optional | ||||||
| 
 | 
 | ||||||
| import py |  | ||||||
| 
 |  | ||||||
| import pytest | import pytest | ||||||
| from _pytest.doctest import _get_checker | from _pytest.doctest import _get_checker | ||||||
| from _pytest.doctest import _is_mocked | from _pytest.doctest import _is_mocked | ||||||
|  | @ -1496,25 +1495,25 @@ def test_warning_on_unwrap_of_broken_object( | ||||||
|     assert inspect.unwrap.__module__ == "inspect" |     assert inspect.unwrap.__module__ == "inspect" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_is_setup_py_not_named_setup_py(tmp_path): | def test_is_setup_py_not_named_setup_py(tmp_path: Path) -> None: | ||||||
|     not_setup_py = tmp_path.joinpath("not_setup.py") |     not_setup_py = tmp_path.joinpath("not_setup.py") | ||||||
|     not_setup_py.write_text('from setuptools import setup; setup(name="foo")') |     not_setup_py.write_text('from setuptools import setup; setup(name="foo")') | ||||||
|     assert not _is_setup_py(py.path.local(str(not_setup_py))) |     assert not _is_setup_py(not_setup_py) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @pytest.mark.parametrize("mod", ("setuptools", "distutils.core")) | @pytest.mark.parametrize("mod", ("setuptools", "distutils.core")) | ||||||
| def test_is_setup_py_is_a_setup_py(tmpdir, mod): | def test_is_setup_py_is_a_setup_py(tmp_path: Path, mod: str) -> None: | ||||||
|     setup_py = tmpdir.join("setup.py") |     setup_py = tmp_path.joinpath("setup.py") | ||||||
|     setup_py.write(f'from {mod} import setup; setup(name="foo")') |     setup_py.write_text(f'from {mod} import setup; setup(name="foo")', "utf-8") | ||||||
|     assert _is_setup_py(setup_py) |     assert _is_setup_py(setup_py) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @pytest.mark.parametrize("mod", ("setuptools", "distutils.core")) | @pytest.mark.parametrize("mod", ("setuptools", "distutils.core")) | ||||||
| def test_is_setup_py_different_encoding(tmp_path, mod): | def test_is_setup_py_different_encoding(tmp_path: Path, mod: str) -> None: | ||||||
|     setup_py = tmp_path.joinpath("setup.py") |     setup_py = tmp_path.joinpath("setup.py") | ||||||
|     contents = ( |     contents = ( | ||||||
|         "# -*- coding: cp1252 -*-\n" |         "# -*- coding: cp1252 -*-\n" | ||||||
|         'from {} import setup; setup(name="foo", description="€")\n'.format(mod) |         'from {} import setup; setup(name="foo", description="€")\n'.format(mod) | ||||||
|     ) |     ) | ||||||
|     setup_py.write_bytes(contents.encode("cp1252")) |     setup_py.write_bytes(contents.encode("cp1252")) | ||||||
|     assert _is_setup_py(py.path.local(str(setup_py))) |     assert _is_setup_py(setup_py) | ||||||
|  |  | ||||||
|  | @ -16,7 +16,6 @@ def test_version_less_verbose(pytester: Pytester, pytestconfig, monkeypatch) -> | ||||||
|     monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") |     monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD") | ||||||
|     result = pytester.runpytest("--version") |     result = pytester.runpytest("--version") | ||||||
|     assert result.ret == 0 |     assert result.ret == 0 | ||||||
|     # p = py.path.local(py.__file__).dirpath() |  | ||||||
|     result.stderr.fnmatch_lines([f"pytest {pytest.__version__}"]) |     result.stderr.fnmatch_lines([f"pytest {pytest.__version__}"]) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
|  | from pathlib import Path | ||||||
| from typing import cast | from typing import cast | ||||||
| from typing import List | from typing import List | ||||||
| from typing import Type | from typing import Type | ||||||
|  | @ -69,23 +70,23 @@ def test_node_warning_enforces_warning_types(pytester: Pytester) -> None: | ||||||
| 
 | 
 | ||||||
| def test__check_initialpaths_for_relpath() -> None: | def test__check_initialpaths_for_relpath() -> None: | ||||||
|     """Ensure that it handles dirs, and does not always use dirname.""" |     """Ensure that it handles dirs, and does not always use dirname.""" | ||||||
|     cwd = py.path.local() |     cwd = Path.cwd() | ||||||
| 
 | 
 | ||||||
|     class FakeSession1: |     class FakeSession1: | ||||||
|         _initialpaths = [cwd] |         _initialpaths = frozenset({cwd}) | ||||||
| 
 | 
 | ||||||
|     session = cast(pytest.Session, FakeSession1) |     session = cast(pytest.Session, FakeSession1) | ||||||
| 
 | 
 | ||||||
|     assert nodes._check_initialpaths_for_relpath(session, cwd) == "" |     assert nodes._check_initialpaths_for_relpath(session, py.path.local(cwd)) == "" | ||||||
| 
 | 
 | ||||||
|     sub = cwd.join("file") |     sub = cwd / "file" | ||||||
| 
 | 
 | ||||||
|     class FakeSession2: |     class FakeSession2: | ||||||
|         _initialpaths = [cwd] |         _initialpaths = frozenset({cwd}) | ||||||
| 
 | 
 | ||||||
|     session = cast(pytest.Session, FakeSession2) |     session = cast(pytest.Session, FakeSession2) | ||||||
| 
 | 
 | ||||||
|     assert nodes._check_initialpaths_for_relpath(session, sub) == "file" |     assert nodes._check_initialpaths_for_relpath(session, py.path.local(sub)) == "file" | ||||||
| 
 | 
 | ||||||
|     outside = py.path.local("/outside") |     outside = py.path.local("/outside") | ||||||
|     assert nodes._check_initialpaths_for_relpath(session, outside) is None |     assert nodes._check_initialpaths_for_relpath(session, outside) is None | ||||||
|  |  | ||||||
|  | @ -1,8 +1,11 @@ | ||||||
| import os.path | import os.path | ||||||
|  | import pickle | ||||||
| import sys | import sys | ||||||
| import unittest.mock | import unittest.mock | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| from textwrap import dedent | from textwrap import dedent | ||||||
|  | from types import ModuleType | ||||||
|  | from typing import Generator | ||||||
| 
 | 
 | ||||||
| import py | import py | ||||||
| 
 | 
 | ||||||
|  | @ -20,6 +23,7 @@ from _pytest.pathlib import maybe_delete_a_numbered_dir | ||||||
| from _pytest.pathlib import resolve_package_path | from _pytest.pathlib import resolve_package_path | ||||||
| from _pytest.pathlib import symlink_or_skip | from _pytest.pathlib import symlink_or_skip | ||||||
| from _pytest.pathlib import visit | from _pytest.pathlib import visit | ||||||
|  | from _pytest.tmpdir import TempPathFactory | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestFNMatcherPort: | class TestFNMatcherPort: | ||||||
|  | @ -96,38 +100,40 @@ class TestImportPath: | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     @pytest.fixture(scope="session") |     @pytest.fixture(scope="session") | ||||||
|     def path1(self, tmpdir_factory): |     def path1(self, tmp_path_factory: TempPathFactory) -> Generator[Path, None, None]: | ||||||
|         path = tmpdir_factory.mktemp("path") |         path = tmp_path_factory.mktemp("path") | ||||||
|         self.setuptestfs(path) |         self.setuptestfs(path) | ||||||
|         yield path |         yield path | ||||||
|         assert path.join("samplefile").check() |         assert path.joinpath("samplefile").exists() | ||||||
| 
 | 
 | ||||||
|     def setuptestfs(self, path): |     def setuptestfs(self, path: Path) -> None: | ||||||
|         # print "setting up test fs for", repr(path) |         # print "setting up test fs for", repr(path) | ||||||
|         samplefile = path.ensure("samplefile") |         samplefile = path / "samplefile" | ||||||
|         samplefile.write("samplefile\n") |         samplefile.write_text("samplefile\n") | ||||||
| 
 | 
 | ||||||
|         execfile = path.ensure("execfile") |         execfile = path / "execfile" | ||||||
|         execfile.write("x=42") |         execfile.write_text("x=42") | ||||||
| 
 | 
 | ||||||
|         execfilepy = path.ensure("execfile.py") |         execfilepy = path / "execfile.py" | ||||||
|         execfilepy.write("x=42") |         execfilepy.write_text("x=42") | ||||||
| 
 | 
 | ||||||
|         d = {1: 2, "hello": "world", "answer": 42} |         d = {1: 2, "hello": "world", "answer": 42} | ||||||
|         path.ensure("samplepickle").dump(d) |         path.joinpath("samplepickle").write_bytes(pickle.dumps(d, 1)) | ||||||
| 
 | 
 | ||||||
|         sampledir = path.ensure("sampledir", dir=1) |         sampledir = path / "sampledir" | ||||||
|         sampledir.ensure("otherfile") |         sampledir.mkdir() | ||||||
|  |         sampledir.joinpath("otherfile").touch() | ||||||
| 
 | 
 | ||||||
|         otherdir = path.ensure("otherdir", dir=1) |         otherdir = path / "otherdir" | ||||||
|         otherdir.ensure("__init__.py") |         otherdir.mkdir() | ||||||
|  |         otherdir.joinpath("__init__.py").touch() | ||||||
| 
 | 
 | ||||||
|         module_a = otherdir.ensure("a.py") |         module_a = otherdir / "a.py" | ||||||
|         module_a.write("from .b import stuff as result\n") |         module_a.write_text("from .b import stuff as result\n") | ||||||
|         module_b = otherdir.ensure("b.py") |         module_b = otherdir / "b.py" | ||||||
|         module_b.write('stuff="got it"\n') |         module_b.write_text('stuff="got it"\n') | ||||||
|         module_c = otherdir.ensure("c.py") |         module_c = otherdir / "c.py" | ||||||
|         module_c.write( |         module_c.write_text( | ||||||
|             dedent( |             dedent( | ||||||
|                 """ |                 """ | ||||||
|             import py; |             import py; | ||||||
|  | @ -136,8 +142,8 @@ class TestImportPath: | ||||||
|         """ |         """ | ||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
|         module_d = otherdir.ensure("d.py") |         module_d = otherdir / "d.py" | ||||||
|         module_d.write( |         module_d.write_text( | ||||||
|             dedent( |             dedent( | ||||||
|                 """ |                 """ | ||||||
|             import py; |             import py; | ||||||
|  | @ -147,122 +153,141 @@ class TestImportPath: | ||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def test_smoke_test(self, path1): |     def test_smoke_test(self, path1: Path) -> None: | ||||||
|         obj = import_path(path1.join("execfile.py")) |         obj = import_path(path1 / "execfile.py") | ||||||
|         assert obj.x == 42  # type: ignore[attr-defined] |         assert obj.x == 42  # type: ignore[attr-defined] | ||||||
|         assert obj.__name__ == "execfile" |         assert obj.__name__ == "execfile" | ||||||
| 
 | 
 | ||||||
|     def test_renamed_dir_creates_mismatch(self, tmpdir, monkeypatch): |     def test_renamed_dir_creates_mismatch( | ||||||
|         p = tmpdir.ensure("a", "test_x123.py") |         self, tmp_path: Path, monkeypatch: MonkeyPatch | ||||||
|  |     ) -> None: | ||||||
|  |         tmp_path.joinpath("a").mkdir() | ||||||
|  |         p = tmp_path.joinpath("a", "test_x123.py") | ||||||
|  |         p.touch() | ||||||
|         import_path(p) |         import_path(p) | ||||||
|         tmpdir.join("a").move(tmpdir.join("b")) |         tmp_path.joinpath("a").rename(tmp_path.joinpath("b")) | ||||||
|         with pytest.raises(ImportPathMismatchError): |         with pytest.raises(ImportPathMismatchError): | ||||||
|             import_path(tmpdir.join("b", "test_x123.py")) |             import_path(tmp_path.joinpath("b", "test_x123.py")) | ||||||
| 
 | 
 | ||||||
|         # Errors can be ignored. |         # Errors can be ignored. | ||||||
|         monkeypatch.setenv("PY_IGNORE_IMPORTMISMATCH", "1") |         monkeypatch.setenv("PY_IGNORE_IMPORTMISMATCH", "1") | ||||||
|         import_path(tmpdir.join("b", "test_x123.py")) |         import_path(tmp_path.joinpath("b", "test_x123.py")) | ||||||
| 
 | 
 | ||||||
|         # PY_IGNORE_IMPORTMISMATCH=0 does not ignore error. |         # PY_IGNORE_IMPORTMISMATCH=0 does not ignore error. | ||||||
|         monkeypatch.setenv("PY_IGNORE_IMPORTMISMATCH", "0") |         monkeypatch.setenv("PY_IGNORE_IMPORTMISMATCH", "0") | ||||||
|         with pytest.raises(ImportPathMismatchError): |         with pytest.raises(ImportPathMismatchError): | ||||||
|             import_path(tmpdir.join("b", "test_x123.py")) |             import_path(tmp_path.joinpath("b", "test_x123.py")) | ||||||
| 
 | 
 | ||||||
|     def test_messy_name(self, tmpdir): |     def test_messy_name(self, tmp_path: Path) -> None: | ||||||
|         # http://bitbucket.org/hpk42/py-trunk/issue/129 |         # http://bitbucket.org/hpk42/py-trunk/issue/129 | ||||||
|         path = tmpdir.ensure("foo__init__.py") |         path = tmp_path / "foo__init__.py" | ||||||
|  |         path.touch() | ||||||
|         module = import_path(path) |         module = import_path(path) | ||||||
|         assert module.__name__ == "foo__init__" |         assert module.__name__ == "foo__init__" | ||||||
| 
 | 
 | ||||||
|     def test_dir(self, tmpdir): |     def test_dir(self, tmp_path: Path) -> None: | ||||||
|         p = tmpdir.join("hello_123") |         p = tmp_path / "hello_123" | ||||||
|         p_init = p.ensure("__init__.py") |         p.mkdir() | ||||||
|  |         p_init = p / "__init__.py" | ||||||
|  |         p_init.touch() | ||||||
|         m = import_path(p) |         m = import_path(p) | ||||||
|         assert m.__name__ == "hello_123" |         assert m.__name__ == "hello_123" | ||||||
|         m = import_path(p_init) |         m = import_path(p_init) | ||||||
|         assert m.__name__ == "hello_123" |         assert m.__name__ == "hello_123" | ||||||
| 
 | 
 | ||||||
|     def test_a(self, path1): |     def test_a(self, path1: Path) -> None: | ||||||
|         otherdir = path1.join("otherdir") |         otherdir = path1 / "otherdir" | ||||||
|         mod = import_path(otherdir.join("a.py")) |         mod = import_path(otherdir / "a.py") | ||||||
|         assert mod.result == "got it"  # type: ignore[attr-defined] |         assert mod.result == "got it"  # type: ignore[attr-defined] | ||||||
|         assert mod.__name__ == "otherdir.a" |         assert mod.__name__ == "otherdir.a" | ||||||
| 
 | 
 | ||||||
|     def test_b(self, path1): |     def test_b(self, path1: Path) -> None: | ||||||
|         otherdir = path1.join("otherdir") |         otherdir = path1 / "otherdir" | ||||||
|         mod = import_path(otherdir.join("b.py")) |         mod = import_path(otherdir / "b.py") | ||||||
|         assert mod.stuff == "got it"  # type: ignore[attr-defined] |         assert mod.stuff == "got it"  # type: ignore[attr-defined] | ||||||
|         assert mod.__name__ == "otherdir.b" |         assert mod.__name__ == "otherdir.b" | ||||||
| 
 | 
 | ||||||
|     def test_c(self, path1): |     def test_c(self, path1: Path) -> None: | ||||||
|         otherdir = path1.join("otherdir") |         otherdir = path1 / "otherdir" | ||||||
|         mod = import_path(otherdir.join("c.py")) |         mod = import_path(otherdir / "c.py") | ||||||
|         assert mod.value == "got it"  # type: ignore[attr-defined] |         assert mod.value == "got it"  # type: ignore[attr-defined] | ||||||
| 
 | 
 | ||||||
|     def test_d(self, path1): |     def test_d(self, path1: Path) -> None: | ||||||
|         otherdir = path1.join("otherdir") |         otherdir = path1 / "otherdir" | ||||||
|         mod = import_path(otherdir.join("d.py")) |         mod = import_path(otherdir / "d.py") | ||||||
|         assert mod.value2 == "got it"  # type: ignore[attr-defined] |         assert mod.value2 == "got it"  # type: ignore[attr-defined] | ||||||
| 
 | 
 | ||||||
|     def test_import_after(self, tmpdir): |     def test_import_after(self, tmp_path: Path) -> None: | ||||||
|         tmpdir.ensure("xxxpackage", "__init__.py") |         tmp_path.joinpath("xxxpackage").mkdir() | ||||||
|         mod1path = tmpdir.ensure("xxxpackage", "module1.py") |         tmp_path.joinpath("xxxpackage", "__init__.py").touch() | ||||||
|  |         mod1path = tmp_path.joinpath("xxxpackage", "module1.py") | ||||||
|  |         mod1path.touch() | ||||||
|         mod1 = import_path(mod1path) |         mod1 = import_path(mod1path) | ||||||
|         assert mod1.__name__ == "xxxpackage.module1" |         assert mod1.__name__ == "xxxpackage.module1" | ||||||
|         from xxxpackage import module1 |         from xxxpackage import module1 | ||||||
| 
 | 
 | ||||||
|         assert module1 is mod1 |         assert module1 is mod1 | ||||||
| 
 | 
 | ||||||
|     def test_check_filepath_consistency(self, monkeypatch, tmpdir): |     def test_check_filepath_consistency( | ||||||
|  |         self, monkeypatch: MonkeyPatch, tmp_path: Path | ||||||
|  |     ) -> None: | ||||||
|         name = "pointsback123" |         name = "pointsback123" | ||||||
|         ModuleType = type(os) |         p = tmp_path.joinpath(name + ".py") | ||||||
|         p = tmpdir.ensure(name + ".py") |         p.touch() | ||||||
|         for ending in (".pyc", ".pyo"): |         for ending in (".pyc", ".pyo"): | ||||||
|             mod = ModuleType(name) |             mod = ModuleType(name) | ||||||
|             pseudopath = tmpdir.ensure(name + ending) |             pseudopath = tmp_path.joinpath(name + ending) | ||||||
|  |             pseudopath.touch() | ||||||
|             mod.__file__ = str(pseudopath) |             mod.__file__ = str(pseudopath) | ||||||
|             monkeypatch.setitem(sys.modules, name, mod) |             monkeypatch.setitem(sys.modules, name, mod) | ||||||
|             newmod = import_path(p) |             newmod = import_path(p) | ||||||
|             assert mod == newmod |             assert mod == newmod | ||||||
|         monkeypatch.undo() |         monkeypatch.undo() | ||||||
|         mod = ModuleType(name) |         mod = ModuleType(name) | ||||||
|         pseudopath = tmpdir.ensure(name + "123.py") |         pseudopath = tmp_path.joinpath(name + "123.py") | ||||||
|  |         pseudopath.touch() | ||||||
|         mod.__file__ = str(pseudopath) |         mod.__file__ = str(pseudopath) | ||||||
|         monkeypatch.setitem(sys.modules, name, mod) |         monkeypatch.setitem(sys.modules, name, mod) | ||||||
|         with pytest.raises(ImportPathMismatchError) as excinfo: |         with pytest.raises(ImportPathMismatchError) as excinfo: | ||||||
|             import_path(p) |             import_path(p) | ||||||
|         modname, modfile, orig = excinfo.value.args |         modname, modfile, orig = excinfo.value.args | ||||||
|         assert modname == name |         assert modname == name | ||||||
|         assert modfile == pseudopath |         assert modfile == str(pseudopath) | ||||||
|         assert orig == p |         assert orig == p | ||||||
|         assert issubclass(ImportPathMismatchError, ImportError) |         assert issubclass(ImportPathMismatchError, ImportError) | ||||||
| 
 | 
 | ||||||
|     def test_issue131_on__init__(self, tmpdir): |     def test_issue131_on__init__(self, tmp_path: Path) -> None: | ||||||
|         # __init__.py files may be namespace packages, and thus the |         # __init__.py files may be namespace packages, and thus the | ||||||
|         # __file__ of an imported module may not be ourselves |         # __file__ of an imported module may not be ourselves | ||||||
|         # see issue |         # see issue | ||||||
|         p1 = tmpdir.ensure("proja", "__init__.py") |         tmp_path.joinpath("proja").mkdir() | ||||||
|         p2 = tmpdir.ensure("sub", "proja", "__init__.py") |         p1 = tmp_path.joinpath("proja", "__init__.py") | ||||||
|  |         p1.touch() | ||||||
|  |         tmp_path.joinpath("sub", "proja").mkdir(parents=True) | ||||||
|  |         p2 = tmp_path.joinpath("sub", "proja", "__init__.py") | ||||||
|  |         p2.touch() | ||||||
|         m1 = import_path(p1) |         m1 = import_path(p1) | ||||||
|         m2 = import_path(p2) |         m2 = import_path(p2) | ||||||
|         assert m1 == m2 |         assert m1 == m2 | ||||||
| 
 | 
 | ||||||
|     def test_ensuresyspath_append(self, tmpdir): |     def test_ensuresyspath_append(self, tmp_path: Path) -> None: | ||||||
|         root1 = tmpdir.mkdir("root1") |         root1 = tmp_path / "root1" | ||||||
|         file1 = root1.ensure("x123.py") |         root1.mkdir() | ||||||
|  |         file1 = root1 / "x123.py" | ||||||
|  |         file1.touch() | ||||||
|         assert str(root1) not in sys.path |         assert str(root1) not in sys.path | ||||||
|         import_path(file1, mode="append") |         import_path(file1, mode="append") | ||||||
|         assert str(root1) == sys.path[-1] |         assert str(root1) == sys.path[-1] | ||||||
|         assert str(root1) not in sys.path[:-1] |         assert str(root1) not in sys.path[:-1] | ||||||
| 
 | 
 | ||||||
|     def test_invalid_path(self, tmpdir): |     def test_invalid_path(self, tmp_path: Path) -> None: | ||||||
|         with pytest.raises(ImportError): |         with pytest.raises(ImportError): | ||||||
|             import_path(tmpdir.join("invalid.py")) |             import_path(tmp_path / "invalid.py") | ||||||
| 
 | 
 | ||||||
|     @pytest.fixture |     @pytest.fixture | ||||||
|     def simple_module(self, tmpdir): |     def simple_module(self, tmp_path: Path) -> Path: | ||||||
|         fn = tmpdir.join("mymod.py") |         fn = tmp_path / "mymod.py" | ||||||
|         fn.write( |         fn.write_text( | ||||||
|             dedent( |             dedent( | ||||||
|                 """ |                 """ | ||||||
|             def foo(x): return 40 + x |             def foo(x): return 40 + x | ||||||
|  | @ -271,19 +296,21 @@ class TestImportPath: | ||||||
|         ) |         ) | ||||||
|         return fn |         return fn | ||||||
| 
 | 
 | ||||||
|     def test_importmode_importlib(self, simple_module): |     def test_importmode_importlib(self, simple_module: Path) -> None: | ||||||
|         """`importlib` mode does not change sys.path.""" |         """`importlib` mode does not change sys.path.""" | ||||||
|         module = import_path(simple_module, mode="importlib") |         module = import_path(simple_module, mode="importlib") | ||||||
|         assert module.foo(2) == 42  # type: ignore[attr-defined] |         assert module.foo(2) == 42  # type: ignore[attr-defined] | ||||||
|         assert simple_module.dirname not in sys.path |         assert str(simple_module.parent) not in sys.path | ||||||
| 
 | 
 | ||||||
|     def test_importmode_twice_is_different_module(self, simple_module): |     def test_importmode_twice_is_different_module(self, simple_module: Path) -> None: | ||||||
|         """`importlib` mode always returns a new module.""" |         """`importlib` mode always returns a new module.""" | ||||||
|         module1 = import_path(simple_module, mode="importlib") |         module1 = import_path(simple_module, mode="importlib") | ||||||
|         module2 = import_path(simple_module, mode="importlib") |         module2 = import_path(simple_module, mode="importlib") | ||||||
|         assert module1 is not module2 |         assert module1 is not module2 | ||||||
| 
 | 
 | ||||||
|     def test_no_meta_path_found(self, simple_module, monkeypatch): |     def test_no_meta_path_found( | ||||||
|  |         self, simple_module: Path, monkeypatch: MonkeyPatch | ||||||
|  |     ) -> None: | ||||||
|         """Even without any meta_path should still import module.""" |         """Even without any meta_path should still import module.""" | ||||||
|         monkeypatch.setattr(sys, "meta_path", []) |         monkeypatch.setattr(sys, "meta_path", []) | ||||||
|         module = import_path(simple_module, mode="importlib") |         module = import_path(simple_module, mode="importlib") | ||||||
|  | @ -299,7 +326,7 @@ class TestImportPath: | ||||||
|             import_path(simple_module, mode="importlib") |             import_path(simple_module, mode="importlib") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_resolve_package_path(tmp_path): | def test_resolve_package_path(tmp_path: Path) -> None: | ||||||
|     pkg = tmp_path / "pkg1" |     pkg = tmp_path / "pkg1" | ||||||
|     pkg.mkdir() |     pkg.mkdir() | ||||||
|     (pkg / "__init__.py").touch() |     (pkg / "__init__.py").touch() | ||||||
|  | @ -309,7 +336,7 @@ def test_resolve_package_path(tmp_path): | ||||||
|     assert resolve_package_path(pkg.joinpath("subdir", "__init__.py")) == pkg |     assert resolve_package_path(pkg.joinpath("subdir", "__init__.py")) == pkg | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_package_unimportable(tmp_path): | def test_package_unimportable(tmp_path: Path) -> None: | ||||||
|     pkg = tmp_path / "pkg1-1" |     pkg = tmp_path / "pkg1-1" | ||||||
|     pkg.mkdir() |     pkg.mkdir() | ||||||
|     pkg.joinpath("__init__.py").touch() |     pkg.joinpath("__init__.py").touch() | ||||||
|  | @ -323,7 +350,7 @@ def test_package_unimportable(tmp_path): | ||||||
|     assert not resolve_package_path(pkg) |     assert not resolve_package_path(pkg) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_access_denied_during_cleanup(tmp_path, monkeypatch): | def test_access_denied_during_cleanup(tmp_path: Path, monkeypatch: MonkeyPatch) -> None: | ||||||
|     """Ensure that deleting a numbered dir does not fail because of OSErrors (#4262).""" |     """Ensure that deleting a numbered dir does not fail because of OSErrors (#4262).""" | ||||||
|     path = tmp_path / "temp-1" |     path = tmp_path / "temp-1" | ||||||
|     path.mkdir() |     path.mkdir() | ||||||
|  | @ -338,7 +365,7 @@ def test_access_denied_during_cleanup(tmp_path, monkeypatch): | ||||||
|     assert not lock_path.is_file() |     assert not lock_path.is_file() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_long_path_during_cleanup(tmp_path): | def test_long_path_during_cleanup(tmp_path: Path) -> None: | ||||||
|     """Ensure that deleting long path works (particularly on Windows (#6775)).""" |     """Ensure that deleting long path works (particularly on Windows (#6775)).""" | ||||||
|     path = (tmp_path / ("a" * 250)).resolve() |     path = (tmp_path / ("a" * 250)).resolve() | ||||||
|     if sys.platform == "win32": |     if sys.platform == "win32": | ||||||
|  | @ -354,14 +381,14 @@ def test_long_path_during_cleanup(tmp_path): | ||||||
|     assert not os.path.isdir(extended_path) |     assert not os.path.isdir(extended_path) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_get_extended_length_path_str(): | def test_get_extended_length_path_str() -> None: | ||||||
|     assert get_extended_length_path_str(r"c:\foo") == r"\\?\c:\foo" |     assert get_extended_length_path_str(r"c:\foo") == r"\\?\c:\foo" | ||||||
|     assert get_extended_length_path_str(r"\\share\foo") == r"\\?\UNC\share\foo" |     assert get_extended_length_path_str(r"\\share\foo") == r"\\?\UNC\share\foo" | ||||||
|     assert get_extended_length_path_str(r"\\?\UNC\share\foo") == r"\\?\UNC\share\foo" |     assert get_extended_length_path_str(r"\\?\UNC\share\foo") == r"\\?\UNC\share\foo" | ||||||
|     assert get_extended_length_path_str(r"\\?\c:\foo") == r"\\?\c:\foo" |     assert get_extended_length_path_str(r"\\?\c:\foo") == r"\\?\c:\foo" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_suppress_error_removing_lock(tmp_path): | def test_suppress_error_removing_lock(tmp_path: Path) -> None: | ||||||
|     """ensure_deletable should be resilient if lock file cannot be removed (#5456, #7491)""" |     """ensure_deletable should be resilient if lock file cannot be removed (#5456, #7491)""" | ||||||
|     path = tmp_path / "dir" |     path = tmp_path / "dir" | ||||||
|     path.mkdir() |     path.mkdir() | ||||||
|  | @ -406,15 +433,14 @@ def test_commonpath() -> None: | ||||||
|     assert commonpath(path, path.parent.parent) == path.parent.parent |     assert commonpath(path, path.parent.parent) == path.parent.parent | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_visit_ignores_errors(tmpdir) -> None: | def test_visit_ignores_errors(tmp_path: Path) -> None: | ||||||
|     symlink_or_skip("recursive", tmpdir.join("recursive")) |     symlink_or_skip("recursive", tmp_path / "recursive") | ||||||
|     tmpdir.join("foo").write_binary(b"") |     tmp_path.joinpath("foo").write_bytes(b"") | ||||||
|     tmpdir.join("bar").write_binary(b"") |     tmp_path.joinpath("bar").write_bytes(b"") | ||||||
| 
 | 
 | ||||||
|     assert [entry.name for entry in visit(tmpdir, recurse=lambda entry: False)] == [ |     assert [ | ||||||
|         "bar", |         entry.name for entry in visit(str(tmp_path), recurse=lambda entry: False) | ||||||
|         "foo", |     ] == ["bar", "foo"] | ||||||
|     ] |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only") | @pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only") | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue