Merge pull request #8174 from bluetech/py-to-pathlib-5

More py.path -> pathlib conversions
This commit is contained in:
Ran Benita 2020-12-26 15:01:07 +02:00 committed by GitHub
commit d8d2df7e6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 333 additions and 291 deletions

View File

@ -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``.

View File

@ -43,6 +43,8 @@ from _pytest._io.saferepr import safeformat
from _pytest._io.saferepr import saferepr
from _pytest.compat import final
from _pytest.compat import get_real_func
from _pytest.pathlib import absolutepath
from _pytest.pathlib import bestrelpath
if TYPE_CHECKING:
from typing_extensions import Literal
@ -78,16 +80,16 @@ class Code:
return self.raw.co_name
@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
case of ``OSError`` / non-existing file."""
if not self.raw.co_filename:
return ""
try:
p = py.path.local(self.raw.co_filename)
p = absolutepath(self.raw.co_filename)
# maybe don't try this checking
if not p.check():
raise OSError("py.path check failed.")
if not p.exists():
raise OSError("path check failed.")
return p
except OSError:
# XXX maybe try harder like the weird logic
@ -223,7 +225,7 @@ class TracebackEntry:
return source.getstatement(self.lineno)
@property
def path(self) -> Union[py.path.local, str]:
def path(self) -> Union[Path, str]:
"""Path to the source code."""
return self.frame.code.path
@ -336,10 +338,10 @@ class Traceback(List[TracebackEntry]):
def cut(
self,
path=None,
path: Optional[Union[Path, str]] = None,
lineno: Optional[int] = None,
firstlineno: Optional[int] = None,
excludepath: Optional[py.path.local] = None,
excludepath: Optional[Path] = None,
) -> "Traceback":
"""Return a Traceback instance wrapping part of this Traceback.
@ -353,17 +355,19 @@ class Traceback(List[TracebackEntry]):
for x in self:
code = x.frame.code
codepath = code.path
if path is not None and codepath != path:
continue
if (
(path is None or codepath == path)
and (
excludepath is None
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)
excludepath is not None
and isinstance(codepath, Path)
and excludepath in codepath.parents
):
return Traceback(x._rawentry, self._excinfo)
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 self
@overload
@ -801,7 +805,8 @@ class FormattedExcinfo:
message = "in %s" % (entry.name)
else:
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)
localsrepr = self.repr_locals(entry.locals)
return ReprEntry(lines, reprargs, localsrepr, reprfileloc, style)
@ -814,15 +819,15 @@ class FormattedExcinfo:
lines.extend(self.get_exconly(excinfo, indent=4))
return ReprEntry(lines, None, None, None, style)
def _makepath(self, path):
if not self.abspath:
def _makepath(self, path: Union[Path, str]) -> str:
if not self.abspath and isinstance(path, Path):
try:
np = py.path.local().bestrelpath(path)
np = bestrelpath(Path.cwd(), path)
except OSError:
return path
return str(path)
if len(np) < len(str(path)):
path = np
return path
return np
return str(path)
def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback":
traceback = excinfo.traceback
@ -1181,7 +1186,7 @@ class ReprFuncArgs(TerminalRepr):
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.
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:
return "", -1
fspath = fn and py.path.local(fn) or ""
fspath = fn and absolutepath(fn) or ""
lineno = -1
if fspath:
try:

View File

@ -128,7 +128,7 @@ def filter_traceback_for_conftest_import_failure(
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,
) -> Union[int, ExitCode]:
"""Perform an in-process test run.
@ -295,13 +295,15 @@ def get_plugin_manager() -> "PytestPluginManager":
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,
) -> "Config":
if args is None:
args = sys.argv[1:]
elif isinstance(args, py.path.local):
args = [str(args)]
# TODO: Remove type-ignore after next mypy release.
# https://github.com/python/typeshed/commit/076983eec45e739c68551cb6119fd7d85fd4afa9
elif isinstance(args, os.PathLike): # type: ignore[misc]
args = [os.fspath(args)]
elif not isinstance(args, list):
msg = "`args` parameter expected to be a list of strings, got: {!r} (type: {})"
raise TypeError(msg.format(args, type(args)))
@ -346,7 +348,7 @@ class PytestPluginManager(PluginManager):
self._conftestpath2mod: Dict[Path, types.ModuleType] = {}
self._confcutdir: Optional[Path] = None
self._noconftest = False
self._duplicatepaths: Set[py.path.local] = set()
self._duplicatepaths: Set[Path] = set()
# plugins that were explicitly skipped with pytest.skip
# list of (module name, skip reason)

View File

@ -36,6 +36,7 @@ from _pytest.config.argparsing import Parser
from _pytest.fixtures import FixtureRequest
from _pytest.nodes import Collector
from _pytest.outcomes import OutcomeException
from _pytest.pathlib import fnmatch_ex
from _pytest.pathlib import import_path
from _pytest.python_api import approx
from _pytest.warning_types import PytestWarning
@ -120,32 +121,32 @@ def pytest_unconfigure() -> None:
def pytest_collect_file(
path: py.path.local, parent: Collector,
fspath: Path, path: py.path.local, parent: Collector,
) -> Optional[Union["DoctestModule", "DoctestTextfile"]]:
config = parent.config
if path.ext == ".py":
if config.option.doctestmodules and not _is_setup_py(path):
if fspath.suffix == ".py":
if config.option.doctestmodules and not _is_setup_py(fspath):
mod: DoctestModule = DoctestModule.from_parent(parent, fspath=path)
return mod
elif _is_doctest(config, path, parent):
elif _is_doctest(config, fspath, parent):
txt: DoctestTextfile = DoctestTextfile.from_parent(parent, fspath=path)
return txt
return None
def _is_setup_py(path: py.path.local) -> bool:
if path.basename != "setup.py":
def _is_setup_py(path: Path) -> bool:
if path.name != "setup.py":
return False
contents = path.read_binary()
contents = path.read_bytes()
return b"setuptools" in contents or b"distutils" in contents
def _is_doctest(config: Config, path: py.path.local, parent) -> bool:
if path.ext in (".txt", ".rst") and parent.session.isinitpath(path):
def _is_doctest(config: Config, path: Path, parent: Collector) -> bool:
if path.suffix in (".txt", ".rst") and parent.session.isinitpath(path):
return True
globs = config.getoption("doctestglob") or ["test*.txt"]
for glob in globs:
if path.check(fnmatch=glob):
if fnmatch_ex(glob, path):
return True
return False

View File

@ -5,6 +5,7 @@ import sys
import warnings
from collections import defaultdict
from collections import deque
from pathlib import Path
from types import TracebackType
from typing import Any
from typing import Callable
@ -58,6 +59,7 @@ from _pytest.mark.structures import MarkDecorator
from _pytest.outcomes import fail
from _pytest.outcomes import TEST_OUTCOME
from _pytest.pathlib import absolutepath
from _pytest.pathlib import bestrelpath
from _pytest.store import StoreKey
if TYPE_CHECKING:
@ -718,7 +720,11 @@ class FixtureRequest:
for fixturedef in self._get_fixturestack():
factory = fixturedef.func
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)
lines.append("%s:%d: def %s%s" % (p, lineno + 1, factory.__name__, args))
return lines

View File

@ -37,6 +37,7 @@ from _pytest.fixtures import FixtureManager
from _pytest.outcomes import exit
from _pytest.pathlib import absolutepath
from _pytest.pathlib import bestrelpath
from _pytest.pathlib import fnmatch_ex
from _pytest.pathlib import visit
from _pytest.reports import CollectReport
from _pytest.reports import TestReport
@ -353,11 +354,14 @@ def pytest_runtestloop(session: "Session") -> bool:
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
checking for the existence of the appropriate activate script."""
bindir = path.join("Scripts" if sys.platform.startswith("win") else "bin")
if not bindir.isdir():
bindir = path.joinpath("Scripts" if sys.platform.startswith("win") else "bin")
try:
if not bindir.is_dir():
return False
except OSError:
return False
activates = (
"activate",
@ -367,33 +371,32 @@ def _in_venv(path: py.path.local) -> bool:
"Activate.bat",
"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]:
path_ = Path(path)
ignore_paths = config._getconftest_pathlist("collect_ignore", path=path_.parent)
def pytest_ignore_collect(fspath: Path, config: Config) -> Optional[bool]:
ignore_paths = config._getconftest_pathlist("collect_ignore", path=fspath.parent)
ignore_paths = ignore_paths or []
excludeopt = config.getoption("ignore")
if excludeopt:
ignore_paths.extend(absolutepath(x) for x in excludeopt)
if path_ in ignore_paths:
if fspath in ignore_paths:
return True
ignore_globs = config._getconftest_pathlist(
"collect_ignore_glob", path=path_.parent
"collect_ignore_glob", path=fspath.parent
)
ignore_globs = ignore_globs or []
excludeglobopt = config.getoption("ignore_glob")
if 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
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 None
@ -538,21 +541,21 @@ class Session(nodes.FSCollector):
if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config):
return False
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 True
def _collectfile(
self, path: py.path.local, handle_dupes: bool = True
self, fspath: Path, handle_dupes: bool = True
) -> Sequence[nodes.Collector]:
fspath = Path(path)
path = py.path.local(fspath)
assert (
path.isfile()
fspath.is_file()
), "{!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)
if not self.isinitpath(path):
ihook = self.gethookproxy(fspath)
if not self.isinitpath(fspath):
if ihook.pytest_ignore_collect(
fspath=fspath, path=path, config=self.config
):
@ -562,10 +565,10 @@ class Session(nodes.FSCollector):
keepduplicates = self.config.getoption("keepduplicates")
if not keepduplicates:
duplicate_paths = self.config.pluginmanager._duplicatepaths
if path in duplicate_paths:
if fspath in duplicate_paths:
return ()
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]
@ -652,10 +655,8 @@ class Session(nodes.FSCollector):
from _pytest.python import Package
# Keep track of any collected nodes in here, so we don't duplicate fixtures.
node_cache1: Dict[py.path.local, Sequence[nodes.Collector]] = {}
node_cache2: Dict[
Tuple[Type[nodes.Collector], py.path.local], nodes.Collector
] = ({})
node_cache1: Dict[Path, Sequence[nodes.Collector]] = {}
node_cache2: Dict[Tuple[Type[nodes.Collector], Path], nodes.Collector] = ({})
# Keep track of any collected collectors in matchnodes paths, so they
# are not collected more than once.
@ -679,31 +680,31 @@ class Session(nodes.FSCollector):
break
if parent.is_dir():
pkginit = py.path.local(parent / "__init__.py")
if pkginit.isfile() and pkginit not in node_cache1:
pkginit = parent / "__init__.py"
if pkginit.is_file() and pkginit not in node_cache1:
col = self._collectfile(pkginit, handle_dupes=False)
if col:
if isinstance(col[0], Package):
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.
# Let the Package collector deal with subnodes, don't collect here.
if argpath.is_dir():
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):
if not direntry.is_file():
continue
path = py.path.local(direntry.path)
dirpath = path.dirpath()
path = Path(direntry.path)
dirpath = path.parent
if dirpath not in seen_dirs:
# Collect packages first.
seen_dirs.add(dirpath)
pkginit = dirpath.join("__init__.py")
pkginit = dirpath / "__init__.py"
if pkginit.exists():
for x in self._collectfile(pkginit):
yield x
@ -714,23 +715,22 @@ class Session(nodes.FSCollector):
continue
for x in self._collectfile(path):
key = (type(x), x.fspath)
if key in node_cache2:
yield node_cache2[key]
key2 = (type(x), Path(x.fspath))
if key2 in node_cache2:
yield node_cache2[key2]
else:
node_cache2[key] = x
node_cache2[key2] = x
yield x
else:
assert argpath.is_file()
argpath_ = py.path.local(argpath)
if argpath_ in node_cache1:
col = node_cache1[argpath_]
if argpath in node_cache1:
col = node_cache1[argpath]
else:
collect_root = pkg_roots.get(argpath_.dirname, self)
col = collect_root._collectfile(argpath_, handle_dupes=False)
collect_root = pkg_roots.get(str(argpath.parent), self)
col = collect_root._collectfile(argpath, handle_dupes=False)
if col:
node_cache1[argpath_] = col
node_cache1[argpath] = col
matching = []
work: List[
@ -846,7 +846,7 @@ def resolve_collection_argument(
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
module paths instead of file-system paths:

View File

@ -39,7 +39,7 @@ if TYPE_CHECKING:
SEP = "/"
tracebackcutdir = py.path.local(_pytest.__file__).dirpath()
tracebackcutdir = Path(_pytest.__file__).parent
def iterparentnodeids(nodeid: str) -> Iterator[str]:
@ -416,9 +416,7 @@ class Node(metaclass=NodeMeta):
return self._repr_failure_py(excinfo, style)
def get_fslocation_from_item(
node: "Node",
) -> Tuple[Union[str, py.path.local], Optional[int]]:
def get_fslocation_from_item(node: "Node") -> Tuple[Union[str, Path], Optional[int]]:
"""Try to extract the actual location from a node, depending on available attributes:
* "location": a pair (path, lineno)
@ -474,7 +472,7 @@ class Collector(Node):
def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None:
if hasattr(self, "fspath"):
traceback = excinfo.traceback
ntraceback = traceback.cut(path=self.fspath)
ntraceback = traceback.cut(path=Path(self.fspath))
if ntraceback == traceback:
ntraceback = ntraceback.cut(excludepath=tracebackcutdir)
excinfo.traceback = ntraceback.filter()

View File

@ -387,7 +387,7 @@ def resolve_from_str(input: str, rootpath: Path) -> Path:
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.
The difference between this algorithm and PurePath.match() is that the

View File

@ -66,6 +66,8 @@ from _pytest.mark.structures import MarkDecorator
from _pytest.mark.structures import normalize_mark_list
from _pytest.outcomes import fail
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 ImportPathMismatchError
from _pytest.pathlib import parts
@ -190,11 +192,10 @@ def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]:
def pytest_collect_file(
fspath: Path, path: py.path.local, parent: nodes.Collector
) -> Optional["Module"]:
ext = path.ext
if ext == ".py":
if fspath.suffix == ".py":
if not parent.session.isinitpath(fspath):
if not path_matches_patterns(
path, parent.config.getini("python_files") + ["__init__.py"]
fspath, parent.config.getini("python_files") + ["__init__.py"]
):
return None
ihook = parent.session.gethookproxy(fspath)
@ -205,13 +206,13 @@ def pytest_collect_file(
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 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":
if path.basename == "__init__.py":
def pytest_pycollect_makemodule(fspath: Path, path: py.path.local, parent) -> "Module":
if fspath.name == "__init__.py":
pkg: Package = Package.from_parent(parent, fspath=path)
return pkg
mod: Module = Module.from_parent(parent, fspath=path)
@ -340,7 +341,11 @@ class PyobjMixin:
fspath: Union[py.path.local, str] = file_path
lineno = compat_co_firstlineno
else:
fspath, lineno = getfslineno(obj)
path, lineno = getfslineno(obj)
if isinstance(path, Path):
fspath = py.path.local(path)
else:
fspath = path
modpath = self.getmodpath()
assert isinstance(lineno, int)
return fspath, lineno, modpath
@ -673,21 +678,21 @@ class Package(Module):
if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config):
return False
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 True
def _collectfile(
self, path: py.path.local, handle_dupes: bool = True
self, fspath: Path, handle_dupes: bool = True
) -> Sequence[nodes.Collector]:
fspath = Path(path)
path = py.path.local(fspath)
assert (
path.isfile()
fspath.is_file()
), "{!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)
if not self.session.isinitpath(path):
ihook = self.session.gethookproxy(fspath)
if not self.session.isinitpath(fspath):
if ihook.pytest_ignore_collect(
fspath=fspath, path=path, config=self.config
):
@ -697,32 +702,32 @@ class Package(Module):
keepduplicates = self.config.getoption("keepduplicates")
if not keepduplicates:
duplicate_paths = self.config.pluginmanager._duplicatepaths
if path in duplicate_paths:
if fspath in duplicate_paths:
return ()
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]
def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
this_path = self.fspath.dirpath()
init_module = this_path.join("__init__.py")
if init_module.check(file=1) and path_matches_patterns(
this_path = Path(self.fspath).parent
init_module = this_path / "__init__.py"
if init_module.is_file() and path_matches_patterns(
init_module, self.config.getini("python_files")
):
yield Module.from_parent(self, fspath=init_module)
pkg_prefixes: Set[py.path.local] = set()
yield Module.from_parent(self, fspath=py.path.local(init_module))
pkg_prefixes: Set[Path] = set()
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.
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
parts_ = parts(direntry.path)
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
):
continue
@ -732,7 +737,7 @@ class Package(Module):
elif not direntry.is_dir():
# Broken symlink or invalid/missing file.
continue
elif path.join("__init__.py").check(file=1):
elif path.joinpath("__init__.py").is_file():
pkg_prefixes.add(path)
@ -1412,13 +1417,13 @@ def _show_fixtures_per_test(config: Config, session: Session) -> None:
import _pytest.config
session.perform_collect()
curdir = py.path.local()
curdir = Path.cwd()
tw = _pytest.config.create_terminal_writer(config)
verbose = config.getvalue("verbose")
def get_best_relpath(func):
def get_best_relpath(func) -> str:
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:
argname = fixture_def.argname
@ -1468,7 +1473,7 @@ def _showfixtures_main(config: Config, session: Session) -> None:
import _pytest.config
session.perform_collect()
curdir = py.path.local()
curdir = Path.cwd()
tw = _pytest.config.create_terminal_writer(config)
verbose = config.getvalue("verbose")
@ -1490,7 +1495,7 @@ def _showfixtures_main(config: Config, session: Session) -> None:
(
len(fixturedef.baseid),
fixturedef.func.__module__,
curdir.bestrelpath(py.path.local(loc)),
bestrelpath(curdir, Path(loc)),
fixturedef.argname,
fixturedef,
)

View File

@ -285,15 +285,13 @@ class WarningReport:
User friendly message about the warning.
:ivar str|None nodeid:
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``).
"""
message = attr.ib(type=str)
nodeid = attr.ib(type=Optional[str], default=None)
fslocation = attr.ib(
type=Optional[Union[Tuple[str, int], py.path.local]], default=None
)
fslocation = attr.ib(type=Optional[Tuple[str, int]], default=None)
count_towards_summary = True
def get_location(self, config: Config) -> Optional[str]:
@ -301,14 +299,9 @@ class WarningReport:
if self.nodeid:
return self.nodeid
if self.fslocation:
if isinstance(self.fslocation, tuple) and len(self.fslocation) >= 2:
filename, linenum = self.fslocation[:2]
relpath = bestrelpath(
config.invocation_params.dir, absolutepath(filename)
)
return f"{relpath}:{linenum}"
else:
return str(self.fslocation)
filename, linenum = self.fslocation
relpath = bestrelpath(config.invocation_params.dir, absolutepath(filename))
return f"{relpath}:{linenum}"
return None

View File

@ -1,7 +1,6 @@
import importlib
import io
import operator
import os
import queue
import sys
import textwrap
@ -12,14 +11,14 @@ from typing import Tuple
from typing import TYPE_CHECKING
from typing import Union
import py
import _pytest
import pytest
from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionInfo
from _pytest._code.code import FormattedExcinfo
from _pytest._io import TerminalWriter
from _pytest.monkeypatch import MonkeyPatch
from _pytest.pathlib import bestrelpath
from _pytest.pathlib import import_path
from _pytest.pytester import LineMatcher
from _pytest.pytester import Pytester
@ -150,9 +149,10 @@ class TestTraceback_f_g_h:
" 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)
path, firstlineno = co.path, co.firstlineno
assert isinstance(path, Path)
traceback = self.excinfo.traceback
newtraceback = traceback.cut(path=path, firstlineno=firstlineno)
assert len(newtraceback) == 1
@ -163,11 +163,11 @@ class TestTraceback_f_g_h:
p = pytester.makepyfile("def f(): raise ValueError")
with pytest.raises(ValueError) as excinfo:
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)
for x in newtraceback:
if hasattr(x, "path"):
assert not py.path.local(x.path).relto(basedir)
assert isinstance(x.path, Path)
assert basedir not in x.path.parents
assert newtraceback[-1].frame.code.path == p
def test_traceback_filter(self):
@ -376,7 +376,7 @@ def test_excinfo_no_python_sourcecode(tmpdir):
for item in excinfo.traceback:
print(item) # XXX: for some reason jinja.Template.render is printed in full
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()}}:"
@ -392,16 +392,16 @@ def test_entrysource_Queue_example():
assert s.startswith("def get")
def test_codepath_Queue_example():
def test_codepath_Queue_example() -> None:
try:
queue.Queue().get(timeout=0.001)
except queue.Empty:
excinfo = _pytest._code.ExceptionInfo.from_current()
entry = excinfo.traceback[-1]
path = entry.path
assert isinstance(path, py.path.local)
assert path.basename.lower() == "queue.py"
assert path.check()
assert isinstance(path, Path)
assert path.name.lower() == "queue.py"
assert path.exists()
def test_match_succeeds():
@ -805,21 +805,21 @@ raise ValueError()
raised = 0
orig_getcwd = os.getcwd
orig_path_cwd = Path.cwd
def raiseos():
nonlocal raised
upframe = sys._getframe().f_back
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
# py38-windows.
raised += 1
raise OSError(2, "custom_oserror")
return orig_getcwd()
return orig_path_cwd()
monkeypatch.setattr(os, "getcwd", raiseos)
assert p._makepath(__file__) == __file__
monkeypatch.setattr(Path, "cwd", raiseos)
assert p._makepath(Path(__file__)) == __file__
assert raised == 1
repr_tb = p.repr_traceback(excinfo)
@ -1015,7 +1015,9 @@ raise ValueError()
assert line.endswith("mod.py")
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(
"""
def f():
@ -1023,25 +1025,22 @@ raise ValueError()
"""
)
excinfo = pytest.raises(ValueError, mod.f)
path = py.path.local(mod.__file__)
old = path.dirpath().chdir()
try:
repr = excinfo.getrepr(abspath=False)
repr.toterminal(tw_mock)
x = py.path.local().bestrelpath(path)
if len(x) < len(str(path)):
msg = tw_mock.get_write_msg(-2)
assert msg == "mod.py"
assert tw_mock.lines[-1] == ":3: ValueError"
repr = excinfo.getrepr(abspath=True)
repr.toterminal(tw_mock)
path = Path(mod.__file__)
monkeypatch.chdir(path.parent)
repr = excinfo.getrepr(abspath=False)
repr.toterminal(tw_mock)
x = bestrelpath(Path.cwd(), path)
if len(x) < len(str(path)):
msg = tw_mock.get_write_msg(-2)
assert msg == path
line = tw_mock.lines[-1]
assert line == ":3: ValueError"
finally:
old.chdir()
assert msg == "mod.py"
assert tw_mock.lines[-1] == ":3: ValueError"
repr = excinfo.getrepr(abspath=True)
repr.toterminal(tw_mock)
msg = tw_mock.get_write_msg(-2)
assert msg == str(path)
line = tw_mock.lines[-1]
assert line == ":3: ValueError"
@pytest.mark.parametrize(
"reproptions",

View File

@ -6,13 +6,12 @@ import inspect
import linecache
import sys
import textwrap
from pathlib import Path
from types import CodeType
from typing import Any
from typing import Dict
from typing import Optional
import py.path
import pytest
from _pytest._code import Code
from _pytest._code import Frame
@ -352,8 +351,8 @@ def test_getfslineno() -> None:
fspath, lineno = getfslineno(f)
assert isinstance(fspath, py.path.local)
assert fspath.basename == "test_source.py"
assert isinstance(fspath, Path)
assert fspath.name == "test_source.py"
assert lineno == f.__code__.co_firstlineno - 1 # see findsource
class A:
@ -362,8 +361,8 @@ def test_getfslineno() -> None:
fspath, lineno = getfslineno(A)
_, A_lineno = inspect.findsource(A)
assert isinstance(fspath, py.path.local)
assert fspath.basename == "test_source.py"
assert isinstance(fspath, Path)
assert fspath.name == "test_source.py"
assert lineno == A_lineno
assert getfslineno(3) == ("", -1)

View File

@ -8,6 +8,7 @@ import pytest
from _pytest.config import ExitCode
from _pytest.monkeypatch import MonkeyPatch
from _pytest.pytester import Pytester
from _pytest.tmpdir import TempPathFactory
pytest_plugins = ("pytester",)
@ -139,9 +140,11 @@ class TestNewAPI:
pytester.runpytest()
assert pytester.path.joinpath(rel_cache_dir).is_dir()
def test_custom_abs_cache_dir(self, pytester: Pytester, tmpdir_factory) -> None:
tmp = str(tmpdir_factory.mktemp("tmp"))
abs_cache_dir = os.path.join(tmp, "custom_cache_dir")
def test_custom_abs_cache_dir(
self, pytester: Pytester, tmp_path_factory: TempPathFactory
) -> None:
tmp = tmp_path_factory.mktemp("tmp")
abs_cache_dir = tmp / "custom_cache_dir"
pytester.makeini(
"""
[pytest]
@ -152,7 +155,7 @@ class TestNewAPI:
)
pytester.makepyfile(test_errored="def test_error():\n assert False")
pytester.runpytest()
assert Path(abs_cache_dir).is_dir()
assert abs_cache_dir.is_dir()
def test_custom_cache_dir_with_env_var(
self, pytester: Pytester, monkeypatch: MonkeyPatch
@ -185,9 +188,9 @@ def test_cache_reportheader(env, pytester: Pytester, monkeypatch: MonkeyPatch) -
def test_cache_reportheader_external_abspath(
pytester: Pytester, tmpdir_factory
pytester: Pytester, tmp_path_factory: TempPathFactory
) -> None:
external_cache = tmpdir_factory.mktemp(
external_cache = tmp_path_factory.mktemp(
"test_cache_reportheader_external_abspath_abs"
)

View File

@ -212,12 +212,12 @@ class TestCollectFS:
bindir = "Scripts" if sys.platform.startswith("win") else "bin"
# no bin/activate, not a virtualenv
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
bin_path = base_path.joinpath(bindir)
bin_path.mkdir()
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:
pytester.makeini(
@ -277,7 +277,7 @@ class TestCollectPluginHookRelay:
wascalled.append(path)
pytester.makefile(".abc", "xyz")
pytest.main(py.path.local(pytester.path), plugins=[Plugin()])
pytest.main(pytester.path, plugins=[Plugin()])
assert len(wascalled) == 1
assert wascalled[0].ext == ".abc"

View File

@ -11,7 +11,6 @@ from typing import Type
from typing import Union
import attr
import py.path
import _pytest._code
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 locate_config
from _pytest.monkeypatch import MonkeyPatch
from _pytest.pathlib import absolutepath
from _pytest.pytester import Pytester
@ -854,8 +854,8 @@ class TestConfigFromdictargs:
)
)
inifile = "../../foo/bar.ini"
option_dict = {"inifilename": inifile, "capture": "no"}
inifilename = "../../foo/bar.ini"
option_dict = {"inifilename": inifilename, "capture": "no"}
cwd = tmp_path.joinpath("a/b")
cwd.mkdir(parents=True)
@ -873,14 +873,14 @@ class TestConfigFromdictargs:
with MonkeyPatch.context() as mp:
mp.chdir(cwd)
config = Config.fromdictargs(option_dict, ())
inipath = py.path.local(inifile)
inipath = absolutepath(inifilename)
assert config.args == [str(cwd)]
assert config.option.inifilename == inifile
assert config.option.inifilename == inifilename
assert config.option.capture == "no"
# 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("should_not_be_set") is None

View File

@ -1,10 +1,9 @@
import inspect
import textwrap
from pathlib import Path
from typing import Callable
from typing import Optional
import py
import pytest
from _pytest.doctest import _get_checker
from _pytest.doctest import _is_mocked
@ -1496,25 +1495,25 @@ def test_warning_on_unwrap_of_broken_object(
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.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"))
def test_is_setup_py_is_a_setup_py(tmpdir, mod):
setup_py = tmpdir.join("setup.py")
setup_py.write(f'from {mod} import setup; setup(name="foo")')
def test_is_setup_py_is_a_setup_py(tmp_path: Path, mod: str) -> None:
setup_py = tmp_path.joinpath("setup.py")
setup_py.write_text(f'from {mod} import setup; setup(name="foo")', "utf-8")
assert _is_setup_py(setup_py)
@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")
contents = (
"# -*- coding: cp1252 -*-\n"
'from {} import setup; setup(name="foo", description="")\n'.format(mod)
)
setup_py.write_bytes(contents.encode("cp1252"))
assert _is_setup_py(py.path.local(str(setup_py)))
assert _is_setup_py(setup_py)

View File

@ -16,7 +16,6 @@ def test_version_less_verbose(pytester: Pytester, pytestconfig, monkeypatch) ->
monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
result = pytester.runpytest("--version")
assert result.ret == 0
# p = py.path.local(py.__file__).dirpath()
result.stderr.fnmatch_lines([f"pytest {pytest.__version__}"])

View File

@ -1,3 +1,4 @@
from pathlib import Path
from typing import cast
from typing import List
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:
"""Ensure that it handles dirs, and does not always use dirname."""
cwd = py.path.local()
cwd = Path.cwd()
class FakeSession1:
_initialpaths = [cwd]
_initialpaths = frozenset({cwd})
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:
_initialpaths = [cwd]
_initialpaths = frozenset({cwd})
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")
assert nodes._check_initialpaths_for_relpath(session, outside) is None

View File

@ -1,8 +1,11 @@
import os.path
import pickle
import sys
import unittest.mock
from pathlib import Path
from textwrap import dedent
from types import ModuleType
from typing import Generator
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 symlink_or_skip
from _pytest.pathlib import visit
from _pytest.tmpdir import TempPathFactory
class TestFNMatcherPort:
@ -96,38 +100,40 @@ class TestImportPath:
"""
@pytest.fixture(scope="session")
def path1(self, tmpdir_factory):
path = tmpdir_factory.mktemp("path")
def path1(self, tmp_path_factory: TempPathFactory) -> Generator[Path, None, None]:
path = tmp_path_factory.mktemp("path")
self.setuptestfs(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)
samplefile = path.ensure("samplefile")
samplefile.write("samplefile\n")
samplefile = path / "samplefile"
samplefile.write_text("samplefile\n")
execfile = path.ensure("execfile")
execfile.write("x=42")
execfile = path / "execfile"
execfile.write_text("x=42")
execfilepy = path.ensure("execfile.py")
execfilepy.write("x=42")
execfilepy = path / "execfile.py"
execfilepy.write_text("x=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.ensure("otherfile")
sampledir = path / "sampledir"
sampledir.mkdir()
sampledir.joinpath("otherfile").touch()
otherdir = path.ensure("otherdir", dir=1)
otherdir.ensure("__init__.py")
otherdir = path / "otherdir"
otherdir.mkdir()
otherdir.joinpath("__init__.py").touch()
module_a = otherdir.ensure("a.py")
module_a.write("from .b import stuff as result\n")
module_b = otherdir.ensure("b.py")
module_b.write('stuff="got it"\n')
module_c = otherdir.ensure("c.py")
module_c.write(
module_a = otherdir / "a.py"
module_a.write_text("from .b import stuff as result\n")
module_b = otherdir / "b.py"
module_b.write_text('stuff="got it"\n')
module_c = otherdir / "c.py"
module_c.write_text(
dedent(
"""
import py;
@ -136,8 +142,8 @@ class TestImportPath:
"""
)
)
module_d = otherdir.ensure("d.py")
module_d.write(
module_d = otherdir / "d.py"
module_d.write_text(
dedent(
"""
import py;
@ -147,122 +153,141 @@ class TestImportPath:
)
)
def test_smoke_test(self, path1):
obj = import_path(path1.join("execfile.py"))
def test_smoke_test(self, path1: Path) -> None:
obj = import_path(path1 / "execfile.py")
assert obj.x == 42 # type: ignore[attr-defined]
assert obj.__name__ == "execfile"
def test_renamed_dir_creates_mismatch(self, tmpdir, monkeypatch):
p = tmpdir.ensure("a", "test_x123.py")
def test_renamed_dir_creates_mismatch(
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)
tmpdir.join("a").move(tmpdir.join("b"))
tmp_path.joinpath("a").rename(tmp_path.joinpath("b"))
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.
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.
monkeypatch.setenv("PY_IGNORE_IMPORTMISMATCH", "0")
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
path = tmpdir.ensure("foo__init__.py")
path = tmp_path / "foo__init__.py"
path.touch()
module = import_path(path)
assert module.__name__ == "foo__init__"
def test_dir(self, tmpdir):
p = tmpdir.join("hello_123")
p_init = p.ensure("__init__.py")
def test_dir(self, tmp_path: Path) -> None:
p = tmp_path / "hello_123"
p.mkdir()
p_init = p / "__init__.py"
p_init.touch()
m = import_path(p)
assert m.__name__ == "hello_123"
m = import_path(p_init)
assert m.__name__ == "hello_123"
def test_a(self, path1):
otherdir = path1.join("otherdir")
mod = import_path(otherdir.join("a.py"))
def test_a(self, path1: Path) -> None:
otherdir = path1 / "otherdir"
mod = import_path(otherdir / "a.py")
assert mod.result == "got it" # type: ignore[attr-defined]
assert mod.__name__ == "otherdir.a"
def test_b(self, path1):
otherdir = path1.join("otherdir")
mod = import_path(otherdir.join("b.py"))
def test_b(self, path1: Path) -> None:
otherdir = path1 / "otherdir"
mod = import_path(otherdir / "b.py")
assert mod.stuff == "got it" # type: ignore[attr-defined]
assert mod.__name__ == "otherdir.b"
def test_c(self, path1):
otherdir = path1.join("otherdir")
mod = import_path(otherdir.join("c.py"))
def test_c(self, path1: Path) -> None:
otherdir = path1 / "otherdir"
mod = import_path(otherdir / "c.py")
assert mod.value == "got it" # type: ignore[attr-defined]
def test_d(self, path1):
otherdir = path1.join("otherdir")
mod = import_path(otherdir.join("d.py"))
def test_d(self, path1: Path) -> None:
otherdir = path1 / "otherdir"
mod = import_path(otherdir / "d.py")
assert mod.value2 == "got it" # type: ignore[attr-defined]
def test_import_after(self, tmpdir):
tmpdir.ensure("xxxpackage", "__init__.py")
mod1path = tmpdir.ensure("xxxpackage", "module1.py")
def test_import_after(self, tmp_path: Path) -> None:
tmp_path.joinpath("xxxpackage").mkdir()
tmp_path.joinpath("xxxpackage", "__init__.py").touch()
mod1path = tmp_path.joinpath("xxxpackage", "module1.py")
mod1path.touch()
mod1 = import_path(mod1path)
assert mod1.__name__ == "xxxpackage.module1"
from xxxpackage import module1
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"
ModuleType = type(os)
p = tmpdir.ensure(name + ".py")
p = tmp_path.joinpath(name + ".py")
p.touch()
for ending in (".pyc", ".pyo"):
mod = ModuleType(name)
pseudopath = tmpdir.ensure(name + ending)
pseudopath = tmp_path.joinpath(name + ending)
pseudopath.touch()
mod.__file__ = str(pseudopath)
monkeypatch.setitem(sys.modules, name, mod)
newmod = import_path(p)
assert mod == newmod
monkeypatch.undo()
mod = ModuleType(name)
pseudopath = tmpdir.ensure(name + "123.py")
pseudopath = tmp_path.joinpath(name + "123.py")
pseudopath.touch()
mod.__file__ = str(pseudopath)
monkeypatch.setitem(sys.modules, name, mod)
with pytest.raises(ImportPathMismatchError) as excinfo:
import_path(p)
modname, modfile, orig = excinfo.value.args
assert modname == name
assert modfile == pseudopath
assert modfile == str(pseudopath)
assert orig == p
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
# __file__ of an imported module may not be ourselves
# see issue
p1 = tmpdir.ensure("proja", "__init__.py")
p2 = tmpdir.ensure("sub", "proja", "__init__.py")
tmp_path.joinpath("proja").mkdir()
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)
m2 = import_path(p2)
assert m1 == m2
def test_ensuresyspath_append(self, tmpdir):
root1 = tmpdir.mkdir("root1")
file1 = root1.ensure("x123.py")
def test_ensuresyspath_append(self, tmp_path: Path) -> None:
root1 = tmp_path / "root1"
root1.mkdir()
file1 = root1 / "x123.py"
file1.touch()
assert str(root1) not in sys.path
import_path(file1, mode="append")
assert str(root1) == 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):
import_path(tmpdir.join("invalid.py"))
import_path(tmp_path / "invalid.py")
@pytest.fixture
def simple_module(self, tmpdir):
fn = tmpdir.join("mymod.py")
fn.write(
def simple_module(self, tmp_path: Path) -> Path:
fn = tmp_path / "mymod.py"
fn.write_text(
dedent(
"""
def foo(x): return 40 + x
@ -271,19 +296,21 @@ class TestImportPath:
)
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."""
module = import_path(simple_module, mode="importlib")
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."""
module1 = import_path(simple_module, mode="importlib")
module2 = import_path(simple_module, mode="importlib")
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."""
monkeypatch.setattr(sys, "meta_path", [])
module = import_path(simple_module, mode="importlib")
@ -299,7 +326,7 @@ class TestImportPath:
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.mkdir()
(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
def test_package_unimportable(tmp_path):
def test_package_unimportable(tmp_path: Path) -> None:
pkg = tmp_path / "pkg1-1"
pkg.mkdir()
pkg.joinpath("__init__.py").touch()
@ -323,7 +350,7 @@ def test_package_unimportable(tmp_path):
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)."""
path = tmp_path / "temp-1"
path.mkdir()
@ -338,7 +365,7 @@ def test_access_denied_during_cleanup(tmp_path, monkeypatch):
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))."""
path = (tmp_path / ("a" * 250)).resolve()
if sys.platform == "win32":
@ -354,14 +381,14 @@ def test_long_path_during_cleanup(tmp_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"\\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"
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)"""
path = tmp_path / "dir"
path.mkdir()
@ -406,15 +433,14 @@ def test_commonpath() -> None:
assert commonpath(path, path.parent.parent) == path.parent.parent
def test_visit_ignores_errors(tmpdir) -> None:
symlink_or_skip("recursive", tmpdir.join("recursive"))
tmpdir.join("foo").write_binary(b"")
tmpdir.join("bar").write_binary(b"")
def test_visit_ignores_errors(tmp_path: Path) -> None:
symlink_or_skip("recursive", tmp_path / "recursive")
tmp_path.joinpath("foo").write_bytes(b"")
tmp_path.joinpath("bar").write_bytes(b"")
assert [entry.name for entry in visit(tmpdir, recurse=lambda entry: False)] == [
"bar",
"foo",
]
assert [
entry.name for entry in visit(str(tmp_path), recurse=lambda entry: False)
] == ["bar", "foo"]
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")