Merge pull request #8144 from bluetech/py-to-pathlib-4
hookspec: add pathlib.Path alternatives to py.path.local parameters in hooks
This commit is contained in:
commit
6c899a0afa
|
@ -0,0 +1,7 @@
|
||||||
|
The following hooks now receive an additional ``pathlib.Path`` argument, equivalent to an existing ``py.path.local`` argument:
|
||||||
|
|
||||||
|
- :func:`pytest_ignore_collect <_pytest.hookspec.pytest_ignore_collect>` - The ``fspath`` parameter (equivalent to existing ``path`` parameter).
|
||||||
|
- :func:`pytest_collect_file <_pytest.hookspec.pytest_collect_file>` - The ``fspath`` parameter (equivalent to existing ``path`` parameter).
|
||||||
|
- :func:`pytest_pycollect_makemodule <_pytest.hookspec.pytest_pycollect_makemodule>` - The ``fspath`` parameter (equivalent to existing ``path`` parameter).
|
||||||
|
- :func:`pytest_report_header <_pytest.hookspec.pytest_report_header>` - The ``startpath`` parameter (equivalent to existing ``startdir`` parameter).
|
||||||
|
- :func:`pytest_report_collectionfinish <_pytest.hookspec.pytest_report_collectionfinish>` - The ``startpath`` parameter (equivalent to existing ``startdir`` parameter).
|
|
@ -27,8 +27,6 @@ from typing import Tuple
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
import py
|
|
||||||
|
|
||||||
from _pytest._io.saferepr import saferepr
|
from _pytest._io.saferepr import saferepr
|
||||||
from _pytest._version import version
|
from _pytest._version import version
|
||||||
from _pytest.assertion import util
|
from _pytest.assertion import util
|
||||||
|
@ -37,6 +35,7 @@ from _pytest.assertion.util import ( # noqa: F401
|
||||||
)
|
)
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
|
from _pytest.pathlib import absolutepath
|
||||||
from _pytest.pathlib import fnmatch_ex
|
from _pytest.pathlib import fnmatch_ex
|
||||||
from _pytest.store import StoreKey
|
from _pytest.store import StoreKey
|
||||||
|
|
||||||
|
@ -215,7 +214,7 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if self.session is not None:
|
if self.session is not None:
|
||||||
if self.session.isinitpath(py.path.local(fn)):
|
if self.session.isinitpath(absolutepath(fn)):
|
||||||
state.trace(f"matched test file (was specified on cmdline): {fn!r}")
|
state.trace(f"matched test file (was specified on cmdline): {fn!r}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import argparse
|
import argparse
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from gettext import gettext
|
from gettext import gettext
|
||||||
|
@ -14,8 +15,6 @@ 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._io
|
import _pytest._io
|
||||||
from _pytest.compat import final
|
from _pytest.compat import final
|
||||||
from _pytest.config.exceptions import UsageError
|
from _pytest.config.exceptions import UsageError
|
||||||
|
@ -97,14 +96,14 @@ class Parser:
|
||||||
|
|
||||||
def parse(
|
def parse(
|
||||||
self,
|
self,
|
||||||
args: Sequence[Union[str, py.path.local]],
|
args: Sequence[Union[str, "os.PathLike[str]"]],
|
||||||
namespace: Optional[argparse.Namespace] = None,
|
namespace: Optional[argparse.Namespace] = None,
|
||||||
) -> argparse.Namespace:
|
) -> argparse.Namespace:
|
||||||
from _pytest._argcomplete import try_argcomplete
|
from _pytest._argcomplete import try_argcomplete
|
||||||
|
|
||||||
self.optparser = self._getparser()
|
self.optparser = self._getparser()
|
||||||
try_argcomplete(self.optparser)
|
try_argcomplete(self.optparser)
|
||||||
strargs = [str(x) if isinstance(x, py.path.local) else x for x in args]
|
strargs = [os.fspath(x) for x in args]
|
||||||
return self.optparser.parse_args(strargs, namespace=namespace)
|
return self.optparser.parse_args(strargs, namespace=namespace)
|
||||||
|
|
||||||
def _getparser(self) -> "MyOptionParser":
|
def _getparser(self) -> "MyOptionParser":
|
||||||
|
@ -128,7 +127,7 @@ class Parser:
|
||||||
|
|
||||||
def parse_setoption(
|
def parse_setoption(
|
||||||
self,
|
self,
|
||||||
args: Sequence[Union[str, py.path.local]],
|
args: Sequence[Union[str, "os.PathLike[str]"]],
|
||||||
option: argparse.Namespace,
|
option: argparse.Namespace,
|
||||||
namespace: Optional[argparse.Namespace] = None,
|
namespace: Optional[argparse.Namespace] = None,
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
|
@ -139,7 +138,7 @@ class Parser:
|
||||||
|
|
||||||
def parse_known_args(
|
def parse_known_args(
|
||||||
self,
|
self,
|
||||||
args: Sequence[Union[str, py.path.local]],
|
args: Sequence[Union[str, "os.PathLike[str]"]],
|
||||||
namespace: Optional[argparse.Namespace] = None,
|
namespace: Optional[argparse.Namespace] = None,
|
||||||
) -> argparse.Namespace:
|
) -> argparse.Namespace:
|
||||||
"""Parse and return a namespace object with known arguments at this point."""
|
"""Parse and return a namespace object with known arguments at this point."""
|
||||||
|
@ -147,13 +146,13 @@ class Parser:
|
||||||
|
|
||||||
def parse_known_and_unknown_args(
|
def parse_known_and_unknown_args(
|
||||||
self,
|
self,
|
||||||
args: Sequence[Union[str, py.path.local]],
|
args: Sequence[Union[str, "os.PathLike[str]"]],
|
||||||
namespace: Optional[argparse.Namespace] = None,
|
namespace: Optional[argparse.Namespace] = None,
|
||||||
) -> Tuple[argparse.Namespace, List[str]]:
|
) -> Tuple[argparse.Namespace, List[str]]:
|
||||||
"""Parse and return a namespace object with known arguments, and
|
"""Parse and return a namespace object with known arguments, and
|
||||||
the remaining arguments unknown at this point."""
|
the remaining arguments unknown at this point."""
|
||||||
optparser = self._getparser()
|
optparser = self._getparser()
|
||||||
strargs = [str(x) if isinstance(x, py.path.local) else x for x in args]
|
strargs = [os.fspath(x) for x in args]
|
||||||
return optparser.parse_known_args(strargs, namespace=namespace)
|
return optparser.parse_known_args(strargs, namespace=namespace)
|
||||||
|
|
||||||
def addini(
|
def addini(
|
||||||
|
|
|
@ -648,12 +648,13 @@ class FixtureRequest:
|
||||||
if has_params:
|
if has_params:
|
||||||
frame = inspect.stack()[3]
|
frame = inspect.stack()[3]
|
||||||
frameinfo = inspect.getframeinfo(frame[0])
|
frameinfo = inspect.getframeinfo(frame[0])
|
||||||
source_path = py.path.local(frameinfo.filename)
|
source_path = absolutepath(frameinfo.filename)
|
||||||
source_lineno = frameinfo.lineno
|
source_lineno = frameinfo.lineno
|
||||||
rel_source_path = source_path.relto(funcitem.config.rootdir)
|
try:
|
||||||
if rel_source_path:
|
source_path_str = str(
|
||||||
source_path_str = rel_source_path
|
source_path.relative_to(funcitem.config.rootpath)
|
||||||
else:
|
)
|
||||||
|
except ValueError:
|
||||||
source_path_str = str(source_path)
|
source_path_str = str(source_path)
|
||||||
msg = (
|
msg = (
|
||||||
"The requested fixture has no parameter defined for test:\n"
|
"The requested fixture has no parameter defined for test:\n"
|
||||||
|
@ -876,7 +877,7 @@ class FixtureLookupError(LookupError):
|
||||||
class FixtureLookupErrorRepr(TerminalRepr):
|
class FixtureLookupErrorRepr(TerminalRepr):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
filename: Union[str, py.path.local],
|
filename: Union[str, "os.PathLike[str]"],
|
||||||
firstlineno: int,
|
firstlineno: int,
|
||||||
tblines: Sequence[str],
|
tblines: Sequence[str],
|
||||||
errorstring: str,
|
errorstring: str,
|
||||||
|
@ -903,7 +904,7 @@ class FixtureLookupErrorRepr(TerminalRepr):
|
||||||
f"{FormattedExcinfo.flow_marker} {line.strip()}", red=True,
|
f"{FormattedExcinfo.flow_marker} {line.strip()}", red=True,
|
||||||
)
|
)
|
||||||
tw.line()
|
tw.line()
|
||||||
tw.line("%s:%d" % (self.filename, self.firstlineno + 1))
|
tw.line("%s:%d" % (os.fspath(self.filename), self.firstlineno + 1))
|
||||||
|
|
||||||
|
|
||||||
def fail_fixturefunc(fixturefunc, msg: str) -> "NoReturn":
|
def fail_fixturefunc(fixturefunc, msg: str) -> "NoReturn":
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""Hook specifications for pytest plugins which are invoked by pytest itself
|
"""Hook specifications for pytest plugins which are invoked by pytest itself
|
||||||
and by builtin plugins."""
|
and by builtin plugins."""
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import List
|
from typing import List
|
||||||
|
@ -261,7 +262,9 @@ def pytest_collection_finish(session: "Session") -> None:
|
||||||
|
|
||||||
|
|
||||||
@hookspec(firstresult=True)
|
@hookspec(firstresult=True)
|
||||||
def pytest_ignore_collect(path: py.path.local, config: "Config") -> Optional[bool]:
|
def pytest_ignore_collect(
|
||||||
|
fspath: Path, path: py.path.local, config: "Config"
|
||||||
|
) -> Optional[bool]:
|
||||||
"""Return True to prevent considering this path for collection.
|
"""Return True to prevent considering this path for collection.
|
||||||
|
|
||||||
This hook is consulted for all files and directories prior to calling
|
This hook is consulted for all files and directories prior to calling
|
||||||
|
@ -269,19 +272,29 @@ def pytest_ignore_collect(path: py.path.local, config: "Config") -> Optional[boo
|
||||||
|
|
||||||
Stops at first non-None result, see :ref:`firstresult`.
|
Stops at first non-None result, see :ref:`firstresult`.
|
||||||
|
|
||||||
|
:param pathlib.Path fspath: The path to analyze.
|
||||||
:param py.path.local path: The path to analyze.
|
:param py.path.local path: The path to analyze.
|
||||||
:param _pytest.config.Config config: The pytest config object.
|
:param _pytest.config.Config config: The pytest config object.
|
||||||
|
|
||||||
|
.. versionchanged:: 6.3.0
|
||||||
|
The ``fspath`` parameter was added as a :class:`pathlib.Path`
|
||||||
|
equivalent of the ``path`` parameter.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def pytest_collect_file(
|
def pytest_collect_file(
|
||||||
path: py.path.local, parent: "Collector"
|
fspath: Path, path: py.path.local, parent: "Collector"
|
||||||
) -> "Optional[Collector]":
|
) -> "Optional[Collector]":
|
||||||
"""Create a Collector for the given path, or None if not relevant.
|
"""Create a Collector for the given path, or None if not relevant.
|
||||||
|
|
||||||
The new node needs to have the specified ``parent`` as a parent.
|
The new node needs to have the specified ``parent`` as a parent.
|
||||||
|
|
||||||
|
:param pathlib.Path fspath: The path to analyze.
|
||||||
:param py.path.local path: The path to collect.
|
:param py.path.local path: The path to collect.
|
||||||
|
|
||||||
|
.. versionchanged:: 6.3.0
|
||||||
|
The ``fspath`` parameter was added as a :class:`pathlib.Path`
|
||||||
|
equivalent of the ``path`` parameter.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -321,7 +334,9 @@ def pytest_make_collect_report(collector: "Collector") -> "Optional[CollectRepor
|
||||||
|
|
||||||
|
|
||||||
@hookspec(firstresult=True)
|
@hookspec(firstresult=True)
|
||||||
def pytest_pycollect_makemodule(path: py.path.local, parent) -> Optional["Module"]:
|
def pytest_pycollect_makemodule(
|
||||||
|
fspath: Path, path: py.path.local, parent
|
||||||
|
) -> Optional["Module"]:
|
||||||
"""Return a Module collector or None for the given path.
|
"""Return a Module collector or None for the given path.
|
||||||
|
|
||||||
This hook will be called for each matching test module path.
|
This hook will be called for each matching test module path.
|
||||||
|
@ -330,7 +345,12 @@ def pytest_pycollect_makemodule(path: py.path.local, parent) -> Optional["Module
|
||||||
|
|
||||||
Stops at first non-None result, see :ref:`firstresult`.
|
Stops at first non-None result, see :ref:`firstresult`.
|
||||||
|
|
||||||
:param py.path.local path: The path of module to collect.
|
:param pathlib.Path fspath: The path of the module to collect.
|
||||||
|
:param py.path.local path: The path of the module to collect.
|
||||||
|
|
||||||
|
.. versionchanged:: 6.3.0
|
||||||
|
The ``fspath`` parameter was added as a :class:`pathlib.Path`
|
||||||
|
equivalent of the ``path`` parameter.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -653,11 +673,12 @@ def pytest_assertion_pass(item: "Item", lineno: int, orig: str, expl: str) -> No
|
||||||
|
|
||||||
|
|
||||||
def pytest_report_header(
|
def pytest_report_header(
|
||||||
config: "Config", startdir: py.path.local
|
config: "Config", startpath: Path, startdir: py.path.local
|
||||||
) -> Union[str, List[str]]:
|
) -> Union[str, List[str]]:
|
||||||
"""Return a string or list of strings to be displayed as header info for terminal reporting.
|
"""Return a string or list of strings to be displayed as header info for terminal reporting.
|
||||||
|
|
||||||
:param _pytest.config.Config config: The pytest config object.
|
:param _pytest.config.Config config: The pytest config object.
|
||||||
|
:param Path startpath: The starting dir.
|
||||||
:param py.path.local startdir: The starting dir.
|
:param py.path.local startdir: The starting dir.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -672,11 +693,15 @@ def pytest_report_header(
|
||||||
This function should be implemented only in plugins or ``conftest.py``
|
This function should be implemented only in plugins or ``conftest.py``
|
||||||
files situated at the tests root directory due to how pytest
|
files situated at the tests root directory due to how pytest
|
||||||
:ref:`discovers plugins during startup <pluginorder>`.
|
:ref:`discovers plugins during startup <pluginorder>`.
|
||||||
|
|
||||||
|
.. versionchanged:: 6.3.0
|
||||||
|
The ``startpath`` parameter was added as a :class:`pathlib.Path`
|
||||||
|
equivalent of the ``startdir`` parameter.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def pytest_report_collectionfinish(
|
def pytest_report_collectionfinish(
|
||||||
config: "Config", startdir: py.path.local, items: Sequence["Item"],
|
config: "Config", startpath: Path, startdir: py.path.local, items: Sequence["Item"],
|
||||||
) -> Union[str, List[str]]:
|
) -> Union[str, List[str]]:
|
||||||
"""Return a string or list of strings to be displayed after collection
|
"""Return a string or list of strings to be displayed after collection
|
||||||
has finished successfully.
|
has finished successfully.
|
||||||
|
@ -686,6 +711,7 @@ def pytest_report_collectionfinish(
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
:param _pytest.config.Config config: The pytest config object.
|
:param _pytest.config.Config config: The pytest config object.
|
||||||
|
:param Path startpath: The starting path.
|
||||||
:param py.path.local startdir: The starting dir.
|
:param py.path.local startdir: The starting dir.
|
||||||
:param items: List of pytest items that are going to be executed; this list should not be modified.
|
:param items: List of pytest items that are going to be executed; this list should not be modified.
|
||||||
|
|
||||||
|
@ -695,6 +721,10 @@ def pytest_report_collectionfinish(
|
||||||
ran before it.
|
ran before it.
|
||||||
If you want to have your line(s) displayed first, use
|
If you want to have your line(s) displayed first, use
|
||||||
:ref:`trylast=True <plugin-hookorder>`.
|
:ref:`trylast=True <plugin-hookorder>`.
|
||||||
|
|
||||||
|
.. versionchanged:: 6.3.0
|
||||||
|
The ``startpath`` parameter was added as a :class:`pathlib.Path`
|
||||||
|
equivalent of the ``startdir`` parameter.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -467,7 +467,7 @@ class Session(nodes.FSCollector):
|
||||||
self.shouldfail: Union[bool, str] = False
|
self.shouldfail: Union[bool, str] = False
|
||||||
self.trace = config.trace.root.get("collection")
|
self.trace = config.trace.root.get("collection")
|
||||||
self.startdir = config.invocation_dir
|
self.startdir = config.invocation_dir
|
||||||
self._initialpaths: FrozenSet[py.path.local] = frozenset()
|
self._initialpaths: FrozenSet[Path] = frozenset()
|
||||||
|
|
||||||
self._bestrelpathcache: Dict[Path, str] = _bestrelpath_cache(config.rootpath)
|
self._bestrelpathcache: Dict[Path, str] = _bestrelpath_cache(config.rootpath)
|
||||||
|
|
||||||
|
@ -510,8 +510,8 @@ class Session(nodes.FSCollector):
|
||||||
|
|
||||||
pytest_collectreport = pytest_runtest_logreport
|
pytest_collectreport = pytest_runtest_logreport
|
||||||
|
|
||||||
def isinitpath(self, path: py.path.local) -> bool:
|
def isinitpath(self, path: Union[str, "os.PathLike[str]"]) -> bool:
|
||||||
return path in self._initialpaths
|
return Path(path) in self._initialpaths
|
||||||
|
|
||||||
def gethookproxy(self, fspath: "os.PathLike[str]"):
|
def gethookproxy(self, fspath: "os.PathLike[str]"):
|
||||||
# Check if we have the common case of running
|
# Check if we have the common case of running
|
||||||
|
@ -532,9 +532,10 @@ class Session(nodes.FSCollector):
|
||||||
def _recurse(self, direntry: "os.DirEntry[str]") -> bool:
|
def _recurse(self, direntry: "os.DirEntry[str]") -> bool:
|
||||||
if direntry.name == "__pycache__":
|
if direntry.name == "__pycache__":
|
||||||
return False
|
return False
|
||||||
path = py.path.local(direntry.path)
|
fspath = Path(direntry.path)
|
||||||
ihook = self.gethookproxy(path.dirpath())
|
path = py.path.local(fspath)
|
||||||
if ihook.pytest_ignore_collect(path=path, config=self.config):
|
ihook = self.gethookproxy(fspath.parent)
|
||||||
|
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(path.check(fnmatch=pat) for pat in norecursepatterns):
|
||||||
|
@ -544,6 +545,7 @@ class Session(nodes.FSCollector):
|
||||||
def _collectfile(
|
def _collectfile(
|
||||||
self, path: py.path.local, handle_dupes: bool = True
|
self, path: py.path.local, handle_dupes: bool = True
|
||||||
) -> Sequence[nodes.Collector]:
|
) -> Sequence[nodes.Collector]:
|
||||||
|
fspath = Path(path)
|
||||||
assert (
|
assert (
|
||||||
path.isfile()
|
path.isfile()
|
||||||
), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(
|
), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(
|
||||||
|
@ -551,7 +553,9 @@ class Session(nodes.FSCollector):
|
||||||
)
|
)
|
||||||
ihook = self.gethookproxy(path)
|
ihook = self.gethookproxy(path)
|
||||||
if not self.isinitpath(path):
|
if not self.isinitpath(path):
|
||||||
if ihook.pytest_ignore_collect(path=path, config=self.config):
|
if ihook.pytest_ignore_collect(
|
||||||
|
fspath=fspath, path=path, config=self.config
|
||||||
|
):
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
if handle_dupes:
|
if handle_dupes:
|
||||||
|
@ -563,7 +567,7 @@ class Session(nodes.FSCollector):
|
||||||
else:
|
else:
|
||||||
duplicate_paths.add(path)
|
duplicate_paths.add(path)
|
||||||
|
|
||||||
return ihook.pytest_collect_file(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]
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def perform_collect(
|
def perform_collect(
|
||||||
|
@ -601,14 +605,14 @@ class Session(nodes.FSCollector):
|
||||||
self.trace.root.indent += 1
|
self.trace.root.indent += 1
|
||||||
|
|
||||||
self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = []
|
self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = []
|
||||||
self._initial_parts: List[Tuple[py.path.local, List[str]]] = []
|
self._initial_parts: List[Tuple[Path, List[str]]] = []
|
||||||
self.items: List[nodes.Item] = []
|
self.items: List[nodes.Item] = []
|
||||||
|
|
||||||
hook = self.config.hook
|
hook = self.config.hook
|
||||||
|
|
||||||
items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items
|
items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items
|
||||||
try:
|
try:
|
||||||
initialpaths: List[py.path.local] = []
|
initialpaths: List[Path] = []
|
||||||
for arg in args:
|
for arg in args:
|
||||||
fspath, parts = resolve_collection_argument(
|
fspath, parts = resolve_collection_argument(
|
||||||
self.config.invocation_params.dir,
|
self.config.invocation_params.dir,
|
||||||
|
@ -669,13 +673,13 @@ class Session(nodes.FSCollector):
|
||||||
# No point in finding packages when collecting doctests.
|
# No point in finding packages when collecting doctests.
|
||||||
if not self.config.getoption("doctestmodules", False):
|
if not self.config.getoption("doctestmodules", False):
|
||||||
pm = self.config.pluginmanager
|
pm = self.config.pluginmanager
|
||||||
confcutdir = py.path.local(pm._confcutdir) if pm._confcutdir else None
|
confcutdir = pm._confcutdir
|
||||||
for parent in reversed(argpath.parts()):
|
for parent in (argpath, *argpath.parents):
|
||||||
if confcutdir and confcutdir.relto(parent):
|
if confcutdir and parent in confcutdir.parents:
|
||||||
break
|
break
|
||||||
|
|
||||||
if parent.isdir():
|
if parent.is_dir():
|
||||||
pkginit = parent.join("__init__.py")
|
pkginit = py.path.local(parent / "__init__.py")
|
||||||
if pkginit.isfile() and pkginit not in node_cache1:
|
if pkginit.isfile() and pkginit not in node_cache1:
|
||||||
col = self._collectfile(pkginit, handle_dupes=False)
|
col = self._collectfile(pkginit, handle_dupes=False)
|
||||||
if col:
|
if col:
|
||||||
|
@ -685,7 +689,7 @@ class Session(nodes.FSCollector):
|
||||||
|
|
||||||
# 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.check(dir=1):
|
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[py.path.local] = set()
|
||||||
|
@ -717,15 +721,16 @@ class Session(nodes.FSCollector):
|
||||||
node_cache2[key] = x
|
node_cache2[key] = x
|
||||||
yield x
|
yield x
|
||||||
else:
|
else:
|
||||||
assert argpath.check(file=1)
|
assert argpath.is_file()
|
||||||
|
|
||||||
if argpath in node_cache1:
|
argpath_ = py.path.local(argpath)
|
||||||
col = node_cache1[argpath]
|
if argpath_ in node_cache1:
|
||||||
|
col = node_cache1[argpath_]
|
||||||
else:
|
else:
|
||||||
collect_root = pkg_roots.get(argpath.dirname, self)
|
collect_root = pkg_roots.get(argpath_.dirname, 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[
|
||||||
|
@ -782,9 +787,7 @@ class Session(nodes.FSCollector):
|
||||||
# first yielded item will be the __init__ Module itself, so
|
# first yielded item will be the __init__ Module itself, so
|
||||||
# just use that. If this special case isn't taken, then all the
|
# just use that. If this special case isn't taken, then all the
|
||||||
# files in the package will be yielded.
|
# files in the package will be yielded.
|
||||||
if argpath.basename == "__init__.py" and isinstance(
|
if argpath.name == "__init__.py" and isinstance(matching[0], Package):
|
||||||
matching[0], Package
|
|
||||||
):
|
|
||||||
try:
|
try:
|
||||||
yield next(iter(matching[0].collect()))
|
yield next(iter(matching[0].collect()))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
|
@ -833,7 +836,7 @@ def search_pypath(module_name: str) -> str:
|
||||||
|
|
||||||
def resolve_collection_argument(
|
def resolve_collection_argument(
|
||||||
invocation_path: Path, arg: str, *, as_pypath: bool = False
|
invocation_path: Path, arg: str, *, as_pypath: bool = False
|
||||||
) -> Tuple[py.path.local, List[str]]:
|
) -> Tuple[Path, List[str]]:
|
||||||
"""Parse path arguments optionally containing selection parts and return (fspath, names).
|
"""Parse path arguments optionally containing selection parts and return (fspath, names).
|
||||||
|
|
||||||
Command-line arguments can point to files and/or directories, and optionally contain
|
Command-line arguments can point to files and/or directories, and optionally contain
|
||||||
|
@ -875,4 +878,4 @@ def resolve_collection_argument(
|
||||||
else "directory argument cannot contain :: selection parts: {arg}"
|
else "directory argument cannot contain :: selection parts: {arg}"
|
||||||
)
|
)
|
||||||
raise UsageError(msg.format(arg=arg))
|
raise UsageError(msg.format(arg=arg))
|
||||||
return py.path.local(str(fspath)), parts
|
return fspath, parts
|
||||||
|
|
|
@ -4,7 +4,6 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
|
@ -325,20 +324,14 @@ class MonkeyPatch:
|
||||||
|
|
||||||
invalidate_caches()
|
invalidate_caches()
|
||||||
|
|
||||||
def chdir(self, path) -> None:
|
def chdir(self, path: Union[str, "os.PathLike[str]"]) -> None:
|
||||||
"""Change the current working directory to the specified path.
|
"""Change the current working directory to the specified path.
|
||||||
|
|
||||||
Path can be a string or a py.path.local object.
|
Path can be a string or a path object.
|
||||||
"""
|
"""
|
||||||
if self._cwd is None:
|
if self._cwd is None:
|
||||||
self._cwd = os.getcwd()
|
self._cwd = os.getcwd()
|
||||||
if hasattr(path, "chdir"):
|
os.chdir(path)
|
||||||
path.chdir()
|
|
||||||
elif isinstance(path, Path):
|
|
||||||
# Modern python uses the fspath protocol here LEGACY
|
|
||||||
os.chdir(str(path))
|
|
||||||
else:
|
|
||||||
os.chdir(path)
|
|
||||||
|
|
||||||
def undo(self) -> None:
|
def undo(self) -> None:
|
||||||
"""Undo previous changes.
|
"""Undo previous changes.
|
||||||
|
|
|
@ -480,10 +480,14 @@ class Collector(Node):
|
||||||
excinfo.traceback = ntraceback.filter()
|
excinfo.traceback = ntraceback.filter()
|
||||||
|
|
||||||
|
|
||||||
def _check_initialpaths_for_relpath(session, fspath):
|
def _check_initialpaths_for_relpath(
|
||||||
|
session: "Session", fspath: py.path.local
|
||||||
|
) -> Optional[str]:
|
||||||
for initial_path in session._initialpaths:
|
for initial_path in session._initialpaths:
|
||||||
if fspath.common(initial_path) == initial_path:
|
initial_path_ = py.path.local(initial_path)
|
||||||
return fspath.relto(initial_path)
|
if fspath.common(initial_path_) == initial_path_:
|
||||||
|
return fspath.relto(initial_path_)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class FSCollector(Collector):
|
class FSCollector(Collector):
|
||||||
|
|
|
@ -30,8 +30,6 @@ from typing import Set
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
import py
|
|
||||||
|
|
||||||
from _pytest.compat import assert_never
|
from _pytest.compat import assert_never
|
||||||
from _pytest.outcomes import skip
|
from _pytest.outcomes import skip
|
||||||
from _pytest.warning_types import PytestWarning
|
from _pytest.warning_types import PytestWarning
|
||||||
|
@ -456,7 +454,7 @@ class ImportPathMismatchError(ImportError):
|
||||||
|
|
||||||
|
|
||||||
def import_path(
|
def import_path(
|
||||||
p: Union[str, py.path.local, Path],
|
p: Union[str, "os.PathLike[str]"],
|
||||||
*,
|
*,
|
||||||
mode: Union[str, ImportMode] = ImportMode.prepend,
|
mode: Union[str, ImportMode] = ImportMode.prepend,
|
||||||
) -> ModuleType:
|
) -> ModuleType:
|
||||||
|
@ -482,7 +480,7 @@ def import_path(
|
||||||
"""
|
"""
|
||||||
mode = ImportMode(mode)
|
mode = ImportMode(mode)
|
||||||
|
|
||||||
path = Path(str(p))
|
path = Path(p)
|
||||||
|
|
||||||
if not path.exists():
|
if not path.exists():
|
||||||
raise ImportError(path)
|
raise ImportError(path)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import warnings
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
@ -187,17 +188,19 @@ def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]:
|
||||||
|
|
||||||
|
|
||||||
def pytest_collect_file(
|
def pytest_collect_file(
|
||||||
path: py.path.local, parent: nodes.Collector
|
fspath: Path, path: py.path.local, parent: nodes.Collector
|
||||||
) -> Optional["Module"]:
|
) -> Optional["Module"]:
|
||||||
ext = path.ext
|
ext = path.ext
|
||||||
if ext == ".py":
|
if ext == ".py":
|
||||||
if not parent.session.isinitpath(path):
|
if not parent.session.isinitpath(fspath):
|
||||||
if not path_matches_patterns(
|
if not path_matches_patterns(
|
||||||
path, parent.config.getini("python_files") + ["__init__.py"]
|
path, parent.config.getini("python_files") + ["__init__.py"]
|
||||||
):
|
):
|
||||||
return None
|
return None
|
||||||
ihook = parent.session.gethookproxy(path)
|
ihook = parent.session.gethookproxy(fspath)
|
||||||
module: Module = ihook.pytest_pycollect_makemodule(path=path, parent=parent)
|
module: Module = ihook.pytest_pycollect_makemodule(
|
||||||
|
fspath=fspath, path=path, parent=parent
|
||||||
|
)
|
||||||
return module
|
return module
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -664,9 +667,10 @@ class Package(Module):
|
||||||
def _recurse(self, direntry: "os.DirEntry[str]") -> bool:
|
def _recurse(self, direntry: "os.DirEntry[str]") -> bool:
|
||||||
if direntry.name == "__pycache__":
|
if direntry.name == "__pycache__":
|
||||||
return False
|
return False
|
||||||
path = py.path.local(direntry.path)
|
fspath = Path(direntry.path)
|
||||||
ihook = self.session.gethookproxy(path.dirpath())
|
path = py.path.local(fspath)
|
||||||
if ihook.pytest_ignore_collect(path=path, config=self.config):
|
ihook = self.session.gethookproxy(fspath.parent)
|
||||||
|
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(path.check(fnmatch=pat) for pat in norecursepatterns):
|
||||||
|
@ -676,6 +680,7 @@ class Package(Module):
|
||||||
def _collectfile(
|
def _collectfile(
|
||||||
self, path: py.path.local, handle_dupes: bool = True
|
self, path: py.path.local, handle_dupes: bool = True
|
||||||
) -> Sequence[nodes.Collector]:
|
) -> Sequence[nodes.Collector]:
|
||||||
|
fspath = Path(path)
|
||||||
assert (
|
assert (
|
||||||
path.isfile()
|
path.isfile()
|
||||||
), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(
|
), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(
|
||||||
|
@ -683,7 +688,9 @@ class Package(Module):
|
||||||
)
|
)
|
||||||
ihook = self.session.gethookproxy(path)
|
ihook = self.session.gethookproxy(path)
|
||||||
if not self.session.isinitpath(path):
|
if not self.session.isinitpath(path):
|
||||||
if ihook.pytest_ignore_collect(path=path, config=self.config):
|
if ihook.pytest_ignore_collect(
|
||||||
|
fspath=fspath, path=path, config=self.config
|
||||||
|
):
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
if handle_dupes:
|
if handle_dupes:
|
||||||
|
@ -695,7 +702,7 @@ class Package(Module):
|
||||||
else:
|
else:
|
||||||
duplicate_paths.add(path)
|
duplicate_paths.add(path)
|
||||||
|
|
||||||
return ihook.pytest_collect_file(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 = self.fspath.dirpath()
|
||||||
|
|
|
@ -710,7 +710,7 @@ class TerminalReporter:
|
||||||
msg += " -- " + str(sys.executable)
|
msg += " -- " + str(sys.executable)
|
||||||
self.write_line(msg)
|
self.write_line(msg)
|
||||||
lines = self.config.hook.pytest_report_header(
|
lines = self.config.hook.pytest_report_header(
|
||||||
config=self.config, startdir=self.startdir
|
config=self.config, startpath=self.startpath, startdir=self.startdir
|
||||||
)
|
)
|
||||||
self._write_report_lines_from_hooks(lines)
|
self._write_report_lines_from_hooks(lines)
|
||||||
|
|
||||||
|
@ -745,7 +745,10 @@ class TerminalReporter:
|
||||||
self.report_collect(True)
|
self.report_collect(True)
|
||||||
|
|
||||||
lines = self.config.hook.pytest_report_collectionfinish(
|
lines = self.config.hook.pytest_report_collectionfinish(
|
||||||
config=self.config, startdir=self.startdir, items=session.items
|
config=self.config,
|
||||||
|
startpath=self.startpath,
|
||||||
|
startdir=self.startdir,
|
||||||
|
items=session.items,
|
||||||
)
|
)
|
||||||
self._write_report_lines_from_hooks(lines)
|
self._write_report_lines_from_hooks(lines)
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@ from typing import Mapping
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Set
|
from typing import Set
|
||||||
|
|
||||||
import py
|
|
||||||
|
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.assertion import util
|
from _pytest.assertion import util
|
||||||
|
@ -1311,7 +1309,7 @@ class TestEarlyRewriteBailout:
|
||||||
import importlib.machinery
|
import importlib.machinery
|
||||||
|
|
||||||
self.find_spec_calls: List[str] = []
|
self.find_spec_calls: List[str] = []
|
||||||
self.initial_paths: Set[py.path.local] = set()
|
self.initial_paths: Set[Path] = set()
|
||||||
|
|
||||||
class StubSession:
|
class StubSession:
|
||||||
_initialpaths = self.initial_paths
|
_initialpaths = self.initial_paths
|
||||||
|
@ -1346,7 +1344,7 @@ class TestEarlyRewriteBailout:
|
||||||
pytester.makepyfile(test_foo="def test_foo(): pass")
|
pytester.makepyfile(test_foo="def test_foo(): pass")
|
||||||
pytester.makepyfile(bar="def bar(): pass")
|
pytester.makepyfile(bar="def bar(): pass")
|
||||||
foobar_path = pytester.makepyfile(foobar="def foobar(): pass")
|
foobar_path = pytester.makepyfile(foobar="def foobar(): pass")
|
||||||
self.initial_paths.add(py.path.local(foobar_path))
|
self.initial_paths.add(foobar_path)
|
||||||
|
|
||||||
# conftest files should always be rewritten
|
# conftest files should always be rewritten
|
||||||
assert hook.find_spec("conftest") is not None
|
assert hook.find_spec("conftest") is not None
|
||||||
|
|
|
@ -4,13 +4,12 @@ import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import py.path
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.config import UsageError
|
from _pytest.config import UsageError
|
||||||
from _pytest.main import resolve_collection_argument
|
from _pytest.main import resolve_collection_argument
|
||||||
from _pytest.main import validate_basetemp
|
from _pytest.main import validate_basetemp
|
||||||
|
from _pytest.pytester import Pytester
|
||||||
from _pytest.pytester import Testdir
|
from _pytest.pytester import Testdir
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,40 +108,37 @@ def test_validate_basetemp_integration(testdir):
|
||||||
|
|
||||||
class TestResolveCollectionArgument:
|
class TestResolveCollectionArgument:
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def invocation_dir(self, testdir: Testdir) -> py.path.local:
|
def invocation_path(self, pytester: Pytester) -> Path:
|
||||||
testdir.syspathinsert(str(testdir.tmpdir / "src"))
|
pytester.syspathinsert(pytester.path / "src")
|
||||||
testdir.chdir()
|
pytester.chdir()
|
||||||
|
|
||||||
pkg = testdir.tmpdir.join("src/pkg").ensure_dir()
|
pkg = pytester.path.joinpath("src/pkg")
|
||||||
pkg.join("__init__.py").ensure()
|
pkg.mkdir(parents=True)
|
||||||
pkg.join("test.py").ensure()
|
pkg.joinpath("__init__.py").touch()
|
||||||
return testdir.tmpdir
|
pkg.joinpath("test.py").touch()
|
||||||
|
return pytester.path
|
||||||
|
|
||||||
@pytest.fixture
|
def test_file(self, invocation_path: Path) -> None:
|
||||||
def invocation_path(self, invocation_dir: py.path.local) -> Path:
|
|
||||||
return Path(str(invocation_dir))
|
|
||||||
|
|
||||||
def test_file(self, invocation_dir: py.path.local, invocation_path: Path) -> None:
|
|
||||||
"""File and parts."""
|
"""File and parts."""
|
||||||
assert resolve_collection_argument(invocation_path, "src/pkg/test.py") == (
|
assert resolve_collection_argument(invocation_path, "src/pkg/test.py") == (
|
||||||
invocation_dir / "src/pkg/test.py",
|
invocation_path / "src/pkg/test.py",
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
assert resolve_collection_argument(invocation_path, "src/pkg/test.py::") == (
|
assert resolve_collection_argument(invocation_path, "src/pkg/test.py::") == (
|
||||||
invocation_dir / "src/pkg/test.py",
|
invocation_path / "src/pkg/test.py",
|
||||||
[""],
|
[""],
|
||||||
)
|
)
|
||||||
assert resolve_collection_argument(
|
assert resolve_collection_argument(
|
||||||
invocation_path, "src/pkg/test.py::foo::bar"
|
invocation_path, "src/pkg/test.py::foo::bar"
|
||||||
) == (invocation_dir / "src/pkg/test.py", ["foo", "bar"])
|
) == (invocation_path / "src/pkg/test.py", ["foo", "bar"])
|
||||||
assert resolve_collection_argument(
|
assert resolve_collection_argument(
|
||||||
invocation_path, "src/pkg/test.py::foo::bar::"
|
invocation_path, "src/pkg/test.py::foo::bar::"
|
||||||
) == (invocation_dir / "src/pkg/test.py", ["foo", "bar", ""])
|
) == (invocation_path / "src/pkg/test.py", ["foo", "bar", ""])
|
||||||
|
|
||||||
def test_dir(self, invocation_dir: py.path.local, invocation_path: Path) -> None:
|
def test_dir(self, invocation_path: Path) -> None:
|
||||||
"""Directory and parts."""
|
"""Directory and parts."""
|
||||||
assert resolve_collection_argument(invocation_path, "src/pkg") == (
|
assert resolve_collection_argument(invocation_path, "src/pkg") == (
|
||||||
invocation_dir / "src/pkg",
|
invocation_path / "src/pkg",
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -156,16 +152,16 @@ class TestResolveCollectionArgument:
|
||||||
):
|
):
|
||||||
resolve_collection_argument(invocation_path, "src/pkg::foo::bar")
|
resolve_collection_argument(invocation_path, "src/pkg::foo::bar")
|
||||||
|
|
||||||
def test_pypath(self, invocation_dir: py.path.local, invocation_path: Path) -> None:
|
def test_pypath(self, invocation_path: Path) -> None:
|
||||||
"""Dotted name and parts."""
|
"""Dotted name and parts."""
|
||||||
assert resolve_collection_argument(
|
assert resolve_collection_argument(
|
||||||
invocation_path, "pkg.test", as_pypath=True
|
invocation_path, "pkg.test", as_pypath=True
|
||||||
) == (invocation_dir / "src/pkg/test.py", [])
|
) == (invocation_path / "src/pkg/test.py", [])
|
||||||
assert resolve_collection_argument(
|
assert resolve_collection_argument(
|
||||||
invocation_path, "pkg.test::foo::bar", as_pypath=True
|
invocation_path, "pkg.test::foo::bar", as_pypath=True
|
||||||
) == (invocation_dir / "src/pkg/test.py", ["foo", "bar"])
|
) == (invocation_path / "src/pkg/test.py", ["foo", "bar"])
|
||||||
assert resolve_collection_argument(invocation_path, "pkg", as_pypath=True) == (
|
assert resolve_collection_argument(invocation_path, "pkg", as_pypath=True) == (
|
||||||
invocation_dir / "src/pkg",
|
invocation_path / "src/pkg",
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -191,13 +187,11 @@ class TestResolveCollectionArgument:
|
||||||
):
|
):
|
||||||
resolve_collection_argument(invocation_path, "foobar", as_pypath=True)
|
resolve_collection_argument(invocation_path, "foobar", as_pypath=True)
|
||||||
|
|
||||||
def test_absolute_paths_are_resolved_correctly(
|
def test_absolute_paths_are_resolved_correctly(self, invocation_path: Path) -> None:
|
||||||
self, invocation_dir: py.path.local, invocation_path: Path
|
|
||||||
) -> None:
|
|
||||||
"""Absolute paths resolve back to absolute paths."""
|
"""Absolute paths resolve back to absolute paths."""
|
||||||
full_path = str(invocation_dir / "src")
|
full_path = str(invocation_path / "src")
|
||||||
assert resolve_collection_argument(invocation_path, full_path) == (
|
assert resolve_collection_argument(invocation_path, full_path) == (
|
||||||
py.path.local(os.path.abspath("src")),
|
Path(os.path.abspath("src")),
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -206,7 +200,7 @@ class TestResolveCollectionArgument:
|
||||||
drive, full_path_without_drive = os.path.splitdrive(full_path)
|
drive, full_path_without_drive = os.path.splitdrive(full_path)
|
||||||
assert resolve_collection_argument(
|
assert resolve_collection_argument(
|
||||||
invocation_path, full_path_without_drive
|
invocation_path, full_path_without_drive
|
||||||
) == (py.path.local(os.path.abspath("src")), [])
|
) == (Path(os.path.abspath("src")), [])
|
||||||
|
|
||||||
|
|
||||||
def test_module_full_path_without_drive(testdir):
|
def test_module_full_path_without_drive(testdir):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from typing import cast
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
@ -73,17 +74,21 @@ def test__check_initialpaths_for_relpath() -> None:
|
||||||
class FakeSession1:
|
class FakeSession1:
|
||||||
_initialpaths = [cwd]
|
_initialpaths = [cwd]
|
||||||
|
|
||||||
assert nodes._check_initialpaths_for_relpath(FakeSession1, cwd) == ""
|
session = cast(pytest.Session, FakeSession1)
|
||||||
|
|
||||||
|
assert nodes._check_initialpaths_for_relpath(session, cwd) == ""
|
||||||
|
|
||||||
sub = cwd.join("file")
|
sub = cwd.join("file")
|
||||||
|
|
||||||
class FakeSession2:
|
class FakeSession2:
|
||||||
_initialpaths = [cwd]
|
_initialpaths = [cwd]
|
||||||
|
|
||||||
assert nodes._check_initialpaths_for_relpath(FakeSession2, sub) == "file"
|
session = cast(pytest.Session, FakeSession2)
|
||||||
|
|
||||||
|
assert nodes._check_initialpaths_for_relpath(session, sub) == "file"
|
||||||
|
|
||||||
outside = py.path.local("/outside")
|
outside = py.path.local("/outside")
|
||||||
assert nodes._check_initialpaths_for_relpath(FakeSession2, outside) is None
|
assert nodes._check_initialpaths_for_relpath(session, outside) is None
|
||||||
|
|
||||||
|
|
||||||
def test_failure_with_changed_cwd(pytester: Pytester) -> None:
|
def test_failure_with_changed_cwd(pytester: Pytester) -> None:
|
||||||
|
|
|
@ -1010,7 +1010,7 @@ class TestTerminalFunctional:
|
||||||
def test_report_collectionfinish_hook(self, pytester: Pytester, params) -> None:
|
def test_report_collectionfinish_hook(self, pytester: Pytester, params) -> None:
|
||||||
pytester.makeconftest(
|
pytester.makeconftest(
|
||||||
"""
|
"""
|
||||||
def pytest_report_collectionfinish(config, startdir, items):
|
def pytest_report_collectionfinish(config, startpath, startdir, items):
|
||||||
return ['hello from hook: {0} items'.format(len(items))]
|
return ['hello from hook: {0} items'.format(len(items))]
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -1436,8 +1436,8 @@ class TestGenericReporting:
|
||||||
)
|
)
|
||||||
pytester.mkdir("a").joinpath("conftest.py").write_text(
|
pytester.mkdir("a").joinpath("conftest.py").write_text(
|
||||||
"""
|
"""
|
||||||
def pytest_report_header(config, startdir):
|
def pytest_report_header(config, startdir, startpath):
|
||||||
return ["line1", str(startdir)]
|
return ["line1", str(startpath)]
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
result = pytester.runpytest("a")
|
result = pytester.runpytest("a")
|
||||||
|
|
Loading…
Reference in New Issue