Merge pull request #9208 from bluetech/legacypath-plugin
Add legacypath plugin, move py.path stuff there
This commit is contained in:
		
						commit
						a53abe93d8
					
				| 
						 | 
				
			
			@ -460,3 +460,7 @@ def setup(app: "sphinx.application.Sphinx") -> None:
 | 
			
		|||
        )
 | 
			
		||||
 | 
			
		||||
    sphinx.pycode.parser.VariableCommentPicker.is_final = patched_is_final
 | 
			
		||||
 | 
			
		||||
    # legacypath.py monkey-patches pytest.Testdir in. Import the file so
 | 
			
		||||
    # that autodoc can discover references to it.
 | 
			
		||||
    import _pytest.legacypath  # noqa: F401
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -638,7 +638,7 @@ tmpdir
 | 
			
		|||
 | 
			
		||||
:ref:`tmpdir and tmpdir_factory`
 | 
			
		||||
 | 
			
		||||
.. autofunction:: _pytest.tmpdir.tmpdir()
 | 
			
		||||
.. autofunction:: _pytest.legacypath.LegacyTmpdirPlugin.tmpdir()
 | 
			
		||||
    :no-auto-options:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,8 +20,6 @@ from .reports import CollectReport
 | 
			
		|||
from _pytest import nodes
 | 
			
		||||
from _pytest._io import TerminalWriter
 | 
			
		||||
from _pytest.compat import final
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.compat import legacy_path
 | 
			
		||||
from _pytest.config import Config
 | 
			
		||||
from _pytest.config import ExitCode
 | 
			
		||||
from _pytest.config import hookimpl
 | 
			
		||||
| 
						 | 
				
			
			@ -142,13 +140,6 @@ class Cache:
 | 
			
		|||
        res.mkdir(exist_ok=True, parents=True)
 | 
			
		||||
        return res
 | 
			
		||||
 | 
			
		||||
    def makedir(self, name: str) -> LEGACY_PATH:
 | 
			
		||||
        """Return a directory path object with the given name.
 | 
			
		||||
 | 
			
		||||
        Same as :func:`mkdir`, but returns a legacy py path instance.
 | 
			
		||||
        """
 | 
			
		||||
        return legacy_path(self.mkdir(name))
 | 
			
		||||
 | 
			
		||||
    def _getvaluepath(self, key: str) -> Path:
 | 
			
		||||
        return self._cachedir.joinpath(self._CACHE_PREFIX_VALUES, Path(key))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,8 +49,6 @@ from _pytest._code import filter_traceback
 | 
			
		|||
from _pytest._io import TerminalWriter
 | 
			
		||||
from _pytest.compat import final
 | 
			
		||||
from _pytest.compat import importlib_metadata
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.compat import legacy_path
 | 
			
		||||
from _pytest.outcomes import fail
 | 
			
		||||
from _pytest.outcomes import Skipped
 | 
			
		||||
from _pytest.pathlib import absolutepath
 | 
			
		||||
| 
						 | 
				
			
			@ -240,6 +238,7 @@ default_plugins = essential_plugins + (
 | 
			
		|||
    "unittest",
 | 
			
		||||
    "capture",
 | 
			
		||||
    "skipping",
 | 
			
		||||
    "legacypath",
 | 
			
		||||
    "tmpdir",
 | 
			
		||||
    "monkeypatch",
 | 
			
		||||
    "recwarn",
 | 
			
		||||
| 
						 | 
				
			
			@ -949,17 +948,6 @@ class Config:
 | 
			
		|||
 | 
			
		||||
            self.cache: Optional[Cache] = None
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def invocation_dir(self) -> LEGACY_PATH:
 | 
			
		||||
        """The directory from which pytest was invoked.
 | 
			
		||||
 | 
			
		||||
        Prefer to use :attr:`invocation_params.dir <InvocationParams.dir>`,
 | 
			
		||||
        which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
        :type: LEGACY_PATH
 | 
			
		||||
        """
 | 
			
		||||
        return legacy_path(str(self.invocation_params.dir))
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def rootpath(self) -> Path:
 | 
			
		||||
        """The path to the :ref:`rootdir <rootdir>`.
 | 
			
		||||
| 
						 | 
				
			
			@ -970,16 +958,6 @@ class Config:
 | 
			
		|||
        """
 | 
			
		||||
        return self._rootpath
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def rootdir(self) -> LEGACY_PATH:
 | 
			
		||||
        """The path to the :ref:`rootdir <rootdir>`.
 | 
			
		||||
 | 
			
		||||
        Prefer to use :attr:`rootpath`, which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
        :type: LEGACY_PATH
 | 
			
		||||
        """
 | 
			
		||||
        return legacy_path(str(self.rootpath))
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def inipath(self) -> Optional[Path]:
 | 
			
		||||
        """The path to the :ref:`configfile <configfiles>`.
 | 
			
		||||
| 
						 | 
				
			
			@ -990,16 +968,6 @@ class Config:
 | 
			
		|||
        """
 | 
			
		||||
        return self._inipath
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def inifile(self) -> Optional[LEGACY_PATH]:
 | 
			
		||||
        """The path to the :ref:`configfile <configfiles>`.
 | 
			
		||||
 | 
			
		||||
        Prefer to use :attr:`inipath`, which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
        :type: Optional[LEGACY_PATH]
 | 
			
		||||
        """
 | 
			
		||||
        return legacy_path(str(self.inipath)) if self.inipath else None
 | 
			
		||||
 | 
			
		||||
    def add_cleanup(self, func: Callable[[], None]) -> None:
 | 
			
		||||
        """Add a function to be called when the config object gets out of
 | 
			
		||||
        use (usually coninciding with pytest_unconfigure)."""
 | 
			
		||||
| 
						 | 
				
			
			@ -1400,6 +1368,12 @@ class Config:
 | 
			
		|||
            self._inicache[name] = val = self._getini(name)
 | 
			
		||||
            return val
 | 
			
		||||
 | 
			
		||||
    # Meant for easy monkeypatching by legacypath plugin.
 | 
			
		||||
    # Can be inlined back (with no cover removed) once legacypath is gone.
 | 
			
		||||
    def _getini_unknown_type(self, name: str, type: str, value: Union[str, List[str]]):
 | 
			
		||||
        msg = f"unknown configuration type: {type}"
 | 
			
		||||
        raise ValueError(msg, value)  # pragma: no cover
 | 
			
		||||
 | 
			
		||||
    def _getini(self, name: str):
 | 
			
		||||
        try:
 | 
			
		||||
            description, type, default = self._parser._inidict[name]
 | 
			
		||||
| 
						 | 
				
			
			@ -1432,13 +1406,7 @@ class Config:
 | 
			
		|||
        #     a_line_list = ["tests", "acceptance"]
 | 
			
		||||
        #   in this case, we already have a list ready to use.
 | 
			
		||||
        #
 | 
			
		||||
        if type == "pathlist":
 | 
			
		||||
            # TODO: This assert is probably not valid in all cases.
 | 
			
		||||
            assert self.inipath is not None
 | 
			
		||||
            dp = self.inipath.parent
 | 
			
		||||
            input_values = shlex.split(value) if isinstance(value, str) else value
 | 
			
		||||
            return [legacy_path(str(dp / x)) for x in input_values]
 | 
			
		||||
        elif type == "paths":
 | 
			
		||||
        if type == "paths":
 | 
			
		||||
            # TODO: This assert is probably not valid in all cases.
 | 
			
		||||
            assert self.inipath is not None
 | 
			
		||||
            dp = self.inipath.parent
 | 
			
		||||
| 
						 | 
				
			
			@ -1453,9 +1421,12 @@ class Config:
 | 
			
		|||
                return value
 | 
			
		||||
        elif type == "bool":
 | 
			
		||||
            return _strtobool(str(value).strip())
 | 
			
		||||
        else:
 | 
			
		||||
            assert type in [None, "string"]
 | 
			
		||||
        elif type == "string":
 | 
			
		||||
            return value
 | 
			
		||||
        elif type is None:
 | 
			
		||||
            return value
 | 
			
		||||
        else:
 | 
			
		||||
            return self._getini_unknown_type(name, type, value)
 | 
			
		||||
 | 
			
		||||
    def _getconftest_pathlist(
 | 
			
		||||
        self, name: str, path: Path, rootpath: Path
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,8 +46,6 @@ from _pytest.compat import getfuncargnames
 | 
			
		|||
from _pytest.compat import getimfunc
 | 
			
		||||
from _pytest.compat import getlocation
 | 
			
		||||
from _pytest.compat import is_generator
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.compat import legacy_path
 | 
			
		||||
from _pytest.compat import NOTSET
 | 
			
		||||
from _pytest.compat import safe_getattr
 | 
			
		||||
from _pytest.config import _PluggyPlugin
 | 
			
		||||
| 
						 | 
				
			
			@ -528,11 +526,6 @@ class FixtureRequest:
 | 
			
		|||
            raise AttributeError(f"module not available in {self.scope}-scoped context")
 | 
			
		||||
        return self._pyfuncitem.getparent(_pytest.python.Module).obj
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def fspath(self) -> LEGACY_PATH:
 | 
			
		||||
        """(deprecated) The file system path of the test module which collected this test."""
 | 
			
		||||
        return legacy_path(self.path)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def path(self) -> Path:
 | 
			
		||||
        if self.scope not in ("function", "class", "module", "package"):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,454 @@
 | 
			
		|||
"""Add backward compatibility support for the legacy py path type."""
 | 
			
		||||
import shlex
 | 
			
		||||
import subprocess
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from typing import List
 | 
			
		||||
from typing import Optional
 | 
			
		||||
from typing import TYPE_CHECKING
 | 
			
		||||
from typing import Union
 | 
			
		||||
 | 
			
		||||
import attr
 | 
			
		||||
from iniconfig import SectionWrapper
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
from _pytest.compat import final
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.compat import legacy_path
 | 
			
		||||
from _pytest.deprecated import check_ispytest
 | 
			
		||||
from _pytest.nodes import Node
 | 
			
		||||
from _pytest.terminal import TerminalReporter
 | 
			
		||||
 | 
			
		||||
if TYPE_CHECKING:
 | 
			
		||||
    from typing_extensions import Final
 | 
			
		||||
 | 
			
		||||
    import pexpect
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@final
 | 
			
		||||
class Testdir:
 | 
			
		||||
    """
 | 
			
		||||
    Similar to :class:`Pytester`, but this class works with legacy legacy_path objects instead.
 | 
			
		||||
 | 
			
		||||
    All methods just forward to an internal :class:`Pytester` instance, converting results
 | 
			
		||||
    to `legacy_path` objects as necessary.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    __test__ = False
 | 
			
		||||
 | 
			
		||||
    CLOSE_STDIN: "Final" = pytest.Pytester.CLOSE_STDIN
 | 
			
		||||
    TimeoutExpired: "Final" = pytest.Pytester.TimeoutExpired
 | 
			
		||||
 | 
			
		||||
    def __init__(self, pytester: pytest.Pytester, *, _ispytest: bool = False) -> None:
 | 
			
		||||
        check_ispytest(_ispytest)
 | 
			
		||||
        self._pytester = pytester
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def tmpdir(self) -> LEGACY_PATH:
 | 
			
		||||
        """Temporary directory where tests are executed."""
 | 
			
		||||
        return legacy_path(self._pytester.path)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def test_tmproot(self) -> LEGACY_PATH:
 | 
			
		||||
        return legacy_path(self._pytester._test_tmproot)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def request(self):
 | 
			
		||||
        return self._pytester._request
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def plugins(self):
 | 
			
		||||
        return self._pytester.plugins
 | 
			
		||||
 | 
			
		||||
    @plugins.setter
 | 
			
		||||
    def plugins(self, plugins):
 | 
			
		||||
        self._pytester.plugins = plugins
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def monkeypatch(self) -> pytest.MonkeyPatch:
 | 
			
		||||
        return self._pytester._monkeypatch
 | 
			
		||||
 | 
			
		||||
    def make_hook_recorder(self, pluginmanager) -> pytest.HookRecorder:
 | 
			
		||||
        """See :meth:`Pytester.make_hook_recorder`."""
 | 
			
		||||
        return self._pytester.make_hook_recorder(pluginmanager)
 | 
			
		||||
 | 
			
		||||
    def chdir(self) -> None:
 | 
			
		||||
        """See :meth:`Pytester.chdir`."""
 | 
			
		||||
        return self._pytester.chdir()
 | 
			
		||||
 | 
			
		||||
    def finalize(self) -> None:
 | 
			
		||||
        """See :meth:`Pytester._finalize`."""
 | 
			
		||||
        return self._pytester._finalize()
 | 
			
		||||
 | 
			
		||||
    def makefile(self, ext, *args, **kwargs) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makefile`."""
 | 
			
		||||
        if ext and not ext.startswith("."):
 | 
			
		||||
            # pytester.makefile is going to throw a ValueError in a way that
 | 
			
		||||
            # testdir.makefile did not, because
 | 
			
		||||
            # pathlib.Path is stricter suffixes than py.path
 | 
			
		||||
            # This ext arguments is likely user error, but since testdir has
 | 
			
		||||
            # allowed this, we will prepend "." as a workaround to avoid breaking
 | 
			
		||||
            # testdir usage that worked before
 | 
			
		||||
            ext = "." + ext
 | 
			
		||||
        return legacy_path(self._pytester.makefile(ext, *args, **kwargs))
 | 
			
		||||
 | 
			
		||||
    def makeconftest(self, source) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makeconftest`."""
 | 
			
		||||
        return legacy_path(self._pytester.makeconftest(source))
 | 
			
		||||
 | 
			
		||||
    def makeini(self, source) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makeini`."""
 | 
			
		||||
        return legacy_path(self._pytester.makeini(source))
 | 
			
		||||
 | 
			
		||||
    def getinicfg(self, source: str) -> SectionWrapper:
 | 
			
		||||
        """See :meth:`Pytester.getinicfg`."""
 | 
			
		||||
        return self._pytester.getinicfg(source)
 | 
			
		||||
 | 
			
		||||
    def makepyprojecttoml(self, source) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makepyprojecttoml`."""
 | 
			
		||||
        return legacy_path(self._pytester.makepyprojecttoml(source))
 | 
			
		||||
 | 
			
		||||
    def makepyfile(self, *args, **kwargs) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makepyfile`."""
 | 
			
		||||
        return legacy_path(self._pytester.makepyfile(*args, **kwargs))
 | 
			
		||||
 | 
			
		||||
    def maketxtfile(self, *args, **kwargs) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.maketxtfile`."""
 | 
			
		||||
        return legacy_path(self._pytester.maketxtfile(*args, **kwargs))
 | 
			
		||||
 | 
			
		||||
    def syspathinsert(self, path=None) -> None:
 | 
			
		||||
        """See :meth:`Pytester.syspathinsert`."""
 | 
			
		||||
        return self._pytester.syspathinsert(path)
 | 
			
		||||
 | 
			
		||||
    def mkdir(self, name) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.mkdir`."""
 | 
			
		||||
        return legacy_path(self._pytester.mkdir(name))
 | 
			
		||||
 | 
			
		||||
    def mkpydir(self, name) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.mkpydir`."""
 | 
			
		||||
        return legacy_path(self._pytester.mkpydir(name))
 | 
			
		||||
 | 
			
		||||
    def copy_example(self, name=None) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.copy_example`."""
 | 
			
		||||
        return legacy_path(self._pytester.copy_example(name))
 | 
			
		||||
 | 
			
		||||
    def getnode(
 | 
			
		||||
        self, config: pytest.Config, arg
 | 
			
		||||
    ) -> Optional[Union[pytest.Item, pytest.Collector]]:
 | 
			
		||||
        """See :meth:`Pytester.getnode`."""
 | 
			
		||||
        return self._pytester.getnode(config, arg)
 | 
			
		||||
 | 
			
		||||
    def getpathnode(self, path):
 | 
			
		||||
        """See :meth:`Pytester.getpathnode`."""
 | 
			
		||||
        return self._pytester.getpathnode(path)
 | 
			
		||||
 | 
			
		||||
    def genitems(
 | 
			
		||||
        self, colitems: List[Union[pytest.Item, pytest.Collector]]
 | 
			
		||||
    ) -> List[pytest.Item]:
 | 
			
		||||
        """See :meth:`Pytester.genitems`."""
 | 
			
		||||
        return self._pytester.genitems(colitems)
 | 
			
		||||
 | 
			
		||||
    def runitem(self, source):
 | 
			
		||||
        """See :meth:`Pytester.runitem`."""
 | 
			
		||||
        return self._pytester.runitem(source)
 | 
			
		||||
 | 
			
		||||
    def inline_runsource(self, source, *cmdlineargs):
 | 
			
		||||
        """See :meth:`Pytester.inline_runsource`."""
 | 
			
		||||
        return self._pytester.inline_runsource(source, *cmdlineargs)
 | 
			
		||||
 | 
			
		||||
    def inline_genitems(self, *args):
 | 
			
		||||
        """See :meth:`Pytester.inline_genitems`."""
 | 
			
		||||
        return self._pytester.inline_genitems(*args)
 | 
			
		||||
 | 
			
		||||
    def inline_run(self, *args, plugins=(), no_reraise_ctrlc: bool = False):
 | 
			
		||||
        """See :meth:`Pytester.inline_run`."""
 | 
			
		||||
        return self._pytester.inline_run(
 | 
			
		||||
            *args, plugins=plugins, no_reraise_ctrlc=no_reraise_ctrlc
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def runpytest_inprocess(self, *args, **kwargs) -> pytest.RunResult:
 | 
			
		||||
        """See :meth:`Pytester.runpytest_inprocess`."""
 | 
			
		||||
        return self._pytester.runpytest_inprocess(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def runpytest(self, *args, **kwargs) -> pytest.RunResult:
 | 
			
		||||
        """See :meth:`Pytester.runpytest`."""
 | 
			
		||||
        return self._pytester.runpytest(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def parseconfig(self, *args) -> pytest.Config:
 | 
			
		||||
        """See :meth:`Pytester.parseconfig`."""
 | 
			
		||||
        return self._pytester.parseconfig(*args)
 | 
			
		||||
 | 
			
		||||
    def parseconfigure(self, *args) -> pytest.Config:
 | 
			
		||||
        """See :meth:`Pytester.parseconfigure`."""
 | 
			
		||||
        return self._pytester.parseconfigure(*args)
 | 
			
		||||
 | 
			
		||||
    def getitem(self, source, funcname="test_func"):
 | 
			
		||||
        """See :meth:`Pytester.getitem`."""
 | 
			
		||||
        return self._pytester.getitem(source, funcname)
 | 
			
		||||
 | 
			
		||||
    def getitems(self, source):
 | 
			
		||||
        """See :meth:`Pytester.getitems`."""
 | 
			
		||||
        return self._pytester.getitems(source)
 | 
			
		||||
 | 
			
		||||
    def getmodulecol(self, source, configargs=(), withinit=False):
 | 
			
		||||
        """See :meth:`Pytester.getmodulecol`."""
 | 
			
		||||
        return self._pytester.getmodulecol(
 | 
			
		||||
            source, configargs=configargs, withinit=withinit
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def collect_by_name(
 | 
			
		||||
        self, modcol: pytest.Collector, name: str
 | 
			
		||||
    ) -> Optional[Union[pytest.Item, pytest.Collector]]:
 | 
			
		||||
        """See :meth:`Pytester.collect_by_name`."""
 | 
			
		||||
        return self._pytester.collect_by_name(modcol, name)
 | 
			
		||||
 | 
			
		||||
    def popen(
 | 
			
		||||
        self,
 | 
			
		||||
        cmdargs,
 | 
			
		||||
        stdout=subprocess.PIPE,
 | 
			
		||||
        stderr=subprocess.PIPE,
 | 
			
		||||
        stdin=CLOSE_STDIN,
 | 
			
		||||
        **kw,
 | 
			
		||||
    ):
 | 
			
		||||
        """See :meth:`Pytester.popen`."""
 | 
			
		||||
        return self._pytester.popen(cmdargs, stdout, stderr, stdin, **kw)
 | 
			
		||||
 | 
			
		||||
    def run(self, *cmdargs, timeout=None, stdin=CLOSE_STDIN) -> pytest.RunResult:
 | 
			
		||||
        """See :meth:`Pytester.run`."""
 | 
			
		||||
        return self._pytester.run(*cmdargs, timeout=timeout, stdin=stdin)
 | 
			
		||||
 | 
			
		||||
    def runpython(self, script) -> pytest.RunResult:
 | 
			
		||||
        """See :meth:`Pytester.runpython`."""
 | 
			
		||||
        return self._pytester.runpython(script)
 | 
			
		||||
 | 
			
		||||
    def runpython_c(self, command):
 | 
			
		||||
        """See :meth:`Pytester.runpython_c`."""
 | 
			
		||||
        return self._pytester.runpython_c(command)
 | 
			
		||||
 | 
			
		||||
    def runpytest_subprocess(self, *args, timeout=None) -> pytest.RunResult:
 | 
			
		||||
        """See :meth:`Pytester.runpytest_subprocess`."""
 | 
			
		||||
        return self._pytester.runpytest_subprocess(*args, timeout=timeout)
 | 
			
		||||
 | 
			
		||||
    def spawn_pytest(
 | 
			
		||||
        self, string: str, expect_timeout: float = 10.0
 | 
			
		||||
    ) -> "pexpect.spawn":
 | 
			
		||||
        """See :meth:`Pytester.spawn_pytest`."""
 | 
			
		||||
        return self._pytester.spawn_pytest(string, expect_timeout=expect_timeout)
 | 
			
		||||
 | 
			
		||||
    def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn":
 | 
			
		||||
        """See :meth:`Pytester.spawn`."""
 | 
			
		||||
        return self._pytester.spawn(cmd, expect_timeout=expect_timeout)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self) -> str:
 | 
			
		||||
        return f"<Testdir {self.tmpdir!r}>"
 | 
			
		||||
 | 
			
		||||
    def __str__(self) -> str:
 | 
			
		||||
        return str(self.tmpdir)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pytest.Testdir = Testdir  # type: ignore[attr-defined]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LegacyTestdirPlugin:
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    @pytest.fixture
 | 
			
		||||
    def testdir(pytester: pytest.Pytester) -> Testdir:
 | 
			
		||||
        """
 | 
			
		||||
        Identical to :fixture:`pytester`, and provides an instance whose methods return
 | 
			
		||||
        legacy ``LEGACY_PATH`` objects instead when applicable.
 | 
			
		||||
 | 
			
		||||
        New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
 | 
			
		||||
        """
 | 
			
		||||
        return Testdir(pytester, _ispytest=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@final
 | 
			
		||||
@attr.s(init=False, auto_attribs=True)
 | 
			
		||||
class TempdirFactory:
 | 
			
		||||
    """Backward compatibility wrapper that implements :class:``_pytest.compat.LEGACY_PATH``
 | 
			
		||||
    for :class:``TempPathFactory``."""
 | 
			
		||||
 | 
			
		||||
    _tmppath_factory: pytest.TempPathFactory
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self, tmppath_factory: pytest.TempPathFactory, *, _ispytest: bool = False
 | 
			
		||||
    ) -> None:
 | 
			
		||||
        check_ispytest(_ispytest)
 | 
			
		||||
        self._tmppath_factory = tmppath_factory
 | 
			
		||||
 | 
			
		||||
    def mktemp(self, basename: str, numbered: bool = True) -> LEGACY_PATH:
 | 
			
		||||
        """Same as :meth:`TempPathFactory.mktemp`, but returns a ``_pytest.compat.LEGACY_PATH`` object."""
 | 
			
		||||
        return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve())
 | 
			
		||||
 | 
			
		||||
    def getbasetemp(self) -> LEGACY_PATH:
 | 
			
		||||
        """Backward compat wrapper for ``_tmppath_factory.getbasetemp``."""
 | 
			
		||||
        return legacy_path(self._tmppath_factory.getbasetemp().resolve())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pytest.TempdirFactory = TempdirFactory  # type: ignore[attr-defined]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LegacyTmpdirPlugin:
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    @pytest.fixture(scope="session")
 | 
			
		||||
    def tmpdir_factory(request: pytest.FixtureRequest) -> TempdirFactory:
 | 
			
		||||
        """Return a :class:`pytest.TempdirFactory` instance for the test session."""
 | 
			
		||||
        # Set dynamically by pytest_configure().
 | 
			
		||||
        return request.config._tmpdirhandler  # type: ignore
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    @pytest.fixture
 | 
			
		||||
    def tmpdir(tmp_path: Path) -> LEGACY_PATH:
 | 
			
		||||
        """Return a temporary directory path object which is unique to each test
 | 
			
		||||
        function invocation, created as a sub directory of the base temporary
 | 
			
		||||
        directory.
 | 
			
		||||
 | 
			
		||||
        By default, a new base temporary directory is created each test session,
 | 
			
		||||
        and old bases are removed after 3 sessions, to aid in debugging. If
 | 
			
		||||
        ``--basetemp`` is used then it is cleared each session. See :ref:`base
 | 
			
		||||
        temporary directory`.
 | 
			
		||||
 | 
			
		||||
        The returned object is a `legacy_path`_ object.
 | 
			
		||||
 | 
			
		||||
        .. _legacy_path: https://py.readthedocs.io/en/latest/path.html
 | 
			
		||||
        """
 | 
			
		||||
        return legacy_path(tmp_path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Cache_makedir(self: pytest.Cache, name: str) -> LEGACY_PATH:
 | 
			
		||||
    """Return a directory path object with the given name.
 | 
			
		||||
 | 
			
		||||
    Same as :func:`mkdir`, but returns a legacy py path instance.
 | 
			
		||||
    """
 | 
			
		||||
    return legacy_path(self.mkdir(name))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def FixtureRequest_fspath(self: pytest.FixtureRequest) -> LEGACY_PATH:
 | 
			
		||||
    """(deprecated) The file system path of the test module which collected this test."""
 | 
			
		||||
    return legacy_path(self.path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def TerminalReporter_startdir(self: TerminalReporter) -> LEGACY_PATH:
 | 
			
		||||
    """The directory from which pytest was invoked.
 | 
			
		||||
 | 
			
		||||
    Prefer to use ``startpath`` which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
    :type: LEGACY_PATH
 | 
			
		||||
    """
 | 
			
		||||
    return legacy_path(self.startpath)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Config_invocation_dir(self: pytest.Config) -> LEGACY_PATH:
 | 
			
		||||
    """The directory from which pytest was invoked.
 | 
			
		||||
 | 
			
		||||
    Prefer to use :attr:`invocation_params.dir <InvocationParams.dir>`,
 | 
			
		||||
    which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
    :type: LEGACY_PATH
 | 
			
		||||
    """
 | 
			
		||||
    return legacy_path(str(self.invocation_params.dir))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Config_rootdir(self: pytest.Config) -> LEGACY_PATH:
 | 
			
		||||
    """The path to the :ref:`rootdir <rootdir>`.
 | 
			
		||||
 | 
			
		||||
    Prefer to use :attr:`rootpath`, which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
    :type: LEGACY_PATH
 | 
			
		||||
    """
 | 
			
		||||
    return legacy_path(str(self.rootpath))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Config_inifile(self: pytest.Config) -> Optional[LEGACY_PATH]:
 | 
			
		||||
    """The path to the :ref:`configfile <configfiles>`.
 | 
			
		||||
 | 
			
		||||
    Prefer to use :attr:`inipath`, which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
    :type: Optional[LEGACY_PATH]
 | 
			
		||||
    """
 | 
			
		||||
    return legacy_path(str(self.inipath)) if self.inipath else None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Session_stardir(self: pytest.Session) -> LEGACY_PATH:
 | 
			
		||||
    """The path from which pytest was invoked.
 | 
			
		||||
 | 
			
		||||
    Prefer to use ``startpath`` which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
    :type: LEGACY_PATH
 | 
			
		||||
    """
 | 
			
		||||
    return legacy_path(self.startpath)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Config__getini_unknown_type(
 | 
			
		||||
    self, name: str, type: str, value: Union[str, List[str]]
 | 
			
		||||
):
 | 
			
		||||
    if type == "pathlist":
 | 
			
		||||
        # TODO: This assert is probably not valid in all cases.
 | 
			
		||||
        assert self.inipath is not None
 | 
			
		||||
        dp = self.inipath.parent
 | 
			
		||||
        input_values = shlex.split(value) if isinstance(value, str) else value
 | 
			
		||||
        return [legacy_path(str(dp / x)) for x in input_values]
 | 
			
		||||
    else:
 | 
			
		||||
        raise ValueError(f"unknown configuration type: {type}", value)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Node_fspath(self: Node) -> LEGACY_PATH:
 | 
			
		||||
    """(deprecated) returns a legacy_path copy of self.path"""
 | 
			
		||||
    return legacy_path(self.path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Node_fspath_set(self: Node, value: LEGACY_PATH) -> None:
 | 
			
		||||
    self.path = Path(value)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def pytest_configure(config: pytest.Config) -> None:
 | 
			
		||||
    mp = pytest.MonkeyPatch()
 | 
			
		||||
    config.add_cleanup(mp.undo)
 | 
			
		||||
 | 
			
		||||
    if config.pluginmanager.has_plugin("pytester"):
 | 
			
		||||
        config.pluginmanager.register(LegacyTestdirPlugin, "legacypath-pytester")
 | 
			
		||||
 | 
			
		||||
    if config.pluginmanager.has_plugin("tmpdir"):
 | 
			
		||||
        # Create TmpdirFactory and attach it to the config object.
 | 
			
		||||
        #
 | 
			
		||||
        # This is to comply with existing plugins which expect the handler to be
 | 
			
		||||
        # available at pytest_configure time, but ideally should be moved entirely
 | 
			
		||||
        # to the tmpdir_factory session fixture.
 | 
			
		||||
        try:
 | 
			
		||||
            tmp_path_factory = config._tmp_path_factory  # type: ignore[attr-defined]
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
            # tmpdir plugin is blocked.
 | 
			
		||||
            pass
 | 
			
		||||
        else:
 | 
			
		||||
            _tmpdirhandler = TempdirFactory(tmp_path_factory, _ispytest=True)
 | 
			
		||||
            mp.setattr(config, "_tmpdirhandler", _tmpdirhandler, raising=False)
 | 
			
		||||
 | 
			
		||||
        config.pluginmanager.register(LegacyTmpdirPlugin, "legacypath-tmpdir")
 | 
			
		||||
 | 
			
		||||
    # Add Cache.makedir().
 | 
			
		||||
    mp.setattr(pytest.Cache, "makedir", Cache_makedir, raising=False)
 | 
			
		||||
 | 
			
		||||
    # Add FixtureRequest.fspath property.
 | 
			
		||||
    mp.setattr(
 | 
			
		||||
        pytest.FixtureRequest, "fspath", property(FixtureRequest_fspath), raising=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Add TerminalReporter.startdir property.
 | 
			
		||||
    mp.setattr(
 | 
			
		||||
        TerminalReporter, "startdir", property(TerminalReporter_startdir), raising=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Add Config.{invocation_dir,rootdir,inifile} properties.
 | 
			
		||||
    mp.setattr(
 | 
			
		||||
        pytest.Config, "invocation_dir", property(Config_invocation_dir), raising=False
 | 
			
		||||
    )
 | 
			
		||||
    mp.setattr(pytest.Config, "rootdir", property(Config_rootdir), raising=False)
 | 
			
		||||
    mp.setattr(pytest.Config, "inifile", property(Config_inifile), raising=False)
 | 
			
		||||
 | 
			
		||||
    # Add Session.startdir property.
 | 
			
		||||
    mp.setattr(pytest.Session, "startdir", property(Session_stardir), raising=False)
 | 
			
		||||
 | 
			
		||||
    # Add pathlist configuration type.
 | 
			
		||||
    mp.setattr(pytest.Config, "_getini_unknown_type", Config__getini_unknown_type)
 | 
			
		||||
 | 
			
		||||
    # Add Node.fspath property.
 | 
			
		||||
    mp.setattr(Node, "fspath", property(Node_fspath, Node_fspath_set), raising=False)
 | 
			
		||||
| 
						 | 
				
			
			@ -25,8 +25,6 @@ import attr
 | 
			
		|||
import _pytest._code
 | 
			
		||||
from _pytest import nodes
 | 
			
		||||
from _pytest.compat import final
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.compat import legacy_path
 | 
			
		||||
from _pytest.config import Config
 | 
			
		||||
from _pytest.config import directory_arg
 | 
			
		||||
from _pytest.config import ExitCode
 | 
			
		||||
| 
						 | 
				
			
			@ -504,16 +502,6 @@ class Session(nodes.FSCollector):
 | 
			
		|||
        """
 | 
			
		||||
        return self.config.invocation_params.dir
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def stardir(self) -> LEGACY_PATH:
 | 
			
		||||
        """The path from which pytest was invoked.
 | 
			
		||||
 | 
			
		||||
        Prefer to use ``startpath`` which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
        :type: LEGACY_PATH
 | 
			
		||||
        """
 | 
			
		||||
        return legacy_path(self.startpath)
 | 
			
		||||
 | 
			
		||||
    def _node_location_to_relpath(self, node_path: Path) -> str:
 | 
			
		||||
        # bestrelpath is a quite slow function.
 | 
			
		||||
        return self._bestrelpathcache[node_path]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,6 @@ from _pytest._code.code import ExceptionInfo
 | 
			
		|||
from _pytest._code.code import TerminalRepr
 | 
			
		||||
from _pytest.compat import cached_property
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.compat import legacy_path
 | 
			
		||||
from _pytest.config import Config
 | 
			
		||||
from _pytest.config import ConftestImportFailure
 | 
			
		||||
from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
 | 
			
		||||
| 
						 | 
				
			
			@ -238,15 +237,6 @@ class Node(metaclass=NodeMeta):
 | 
			
		|||
        # Deprecated alias. Was never public. Can be removed in a few releases.
 | 
			
		||||
        self._store = self.stash
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def fspath(self) -> LEGACY_PATH:
 | 
			
		||||
        """(deprecated) returns a legacy_path copy of self.path"""
 | 
			
		||||
        return legacy_path(self.path)
 | 
			
		||||
 | 
			
		||||
    @fspath.setter
 | 
			
		||||
    def fspath(self, value: LEGACY_PATH) -> None:
 | 
			
		||||
        self.path = Path(value)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_parent(cls, parent: "Node", **kw):
 | 
			
		||||
        """Public constructor for Nodes.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,8 +40,6 @@ from _pytest import timing
 | 
			
		|||
from _pytest._code import Source
 | 
			
		||||
from _pytest.capture import _get_multicapture
 | 
			
		||||
from _pytest.compat import final
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.compat import legacy_path
 | 
			
		||||
from _pytest.compat import NOTSET
 | 
			
		||||
from _pytest.compat import NotSetType
 | 
			
		||||
from _pytest.config import _PluggyPlugin
 | 
			
		||||
| 
						 | 
				
			
			@ -493,17 +491,6 @@ def pytester(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> "Pyt
 | 
			
		|||
    return Pytester(request, tmp_path_factory, _ispytest=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@fixture
 | 
			
		||||
def testdir(pytester: "Pytester") -> "Testdir":
 | 
			
		||||
    """
 | 
			
		||||
    Identical to :fixture:`pytester`, and provides an instance whose methods return
 | 
			
		||||
    legacy ``LEGACY_PATH`` objects instead when applicable.
 | 
			
		||||
 | 
			
		||||
    New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
 | 
			
		||||
    """
 | 
			
		||||
    return Testdir(pytester, _ispytest=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@fixture
 | 
			
		||||
def _sys_snapshot() -> Generator[None, None, None]:
 | 
			
		||||
    snappaths = SysPathsSnapshot()
 | 
			
		||||
| 
						 | 
				
			
			@ -1531,224 +1518,6 @@ class LineComp:
 | 
			
		|||
        LineMatcher(lines1).fnmatch_lines(lines2)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@final
 | 
			
		||||
class Testdir:
 | 
			
		||||
    """
 | 
			
		||||
    Similar to :class:`Pytester`, but this class works with legacy legacy_path objects instead.
 | 
			
		||||
 | 
			
		||||
    All methods just forward to an internal :class:`Pytester` instance, converting results
 | 
			
		||||
    to `legacy_path` objects as necessary.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    __test__ = False
 | 
			
		||||
 | 
			
		||||
    CLOSE_STDIN: "Final" = Pytester.CLOSE_STDIN
 | 
			
		||||
    TimeoutExpired: "Final" = Pytester.TimeoutExpired
 | 
			
		||||
 | 
			
		||||
    def __init__(self, pytester: Pytester, *, _ispytest: bool = False) -> None:
 | 
			
		||||
        check_ispytest(_ispytest)
 | 
			
		||||
        self._pytester = pytester
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def tmpdir(self) -> LEGACY_PATH:
 | 
			
		||||
        """Temporary directory where tests are executed."""
 | 
			
		||||
        return legacy_path(self._pytester.path)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def test_tmproot(self) -> LEGACY_PATH:
 | 
			
		||||
        return legacy_path(self._pytester._test_tmproot)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def request(self):
 | 
			
		||||
        return self._pytester._request
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def plugins(self):
 | 
			
		||||
        return self._pytester.plugins
 | 
			
		||||
 | 
			
		||||
    @plugins.setter
 | 
			
		||||
    def plugins(self, plugins):
 | 
			
		||||
        self._pytester.plugins = plugins
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def monkeypatch(self) -> MonkeyPatch:
 | 
			
		||||
        return self._pytester._monkeypatch
 | 
			
		||||
 | 
			
		||||
    def make_hook_recorder(self, pluginmanager) -> HookRecorder:
 | 
			
		||||
        """See :meth:`Pytester.make_hook_recorder`."""
 | 
			
		||||
        return self._pytester.make_hook_recorder(pluginmanager)
 | 
			
		||||
 | 
			
		||||
    def chdir(self) -> None:
 | 
			
		||||
        """See :meth:`Pytester.chdir`."""
 | 
			
		||||
        return self._pytester.chdir()
 | 
			
		||||
 | 
			
		||||
    def finalize(self) -> None:
 | 
			
		||||
        """See :meth:`Pytester._finalize`."""
 | 
			
		||||
        return self._pytester._finalize()
 | 
			
		||||
 | 
			
		||||
    def makefile(self, ext, *args, **kwargs) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makefile`."""
 | 
			
		||||
        if ext and not ext.startswith("."):
 | 
			
		||||
            # pytester.makefile is going to throw a ValueError in a way that
 | 
			
		||||
            # testdir.makefile did not, because
 | 
			
		||||
            # pathlib.Path is stricter suffixes than py.path
 | 
			
		||||
            # This ext arguments is likely user error, but since testdir has
 | 
			
		||||
            # allowed this, we will prepend "." as a workaround to avoid breaking
 | 
			
		||||
            # testdir usage that worked before
 | 
			
		||||
            ext = "." + ext
 | 
			
		||||
        return legacy_path(self._pytester.makefile(ext, *args, **kwargs))
 | 
			
		||||
 | 
			
		||||
    def makeconftest(self, source) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makeconftest`."""
 | 
			
		||||
        return legacy_path(self._pytester.makeconftest(source))
 | 
			
		||||
 | 
			
		||||
    def makeini(self, source) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makeini`."""
 | 
			
		||||
        return legacy_path(self._pytester.makeini(source))
 | 
			
		||||
 | 
			
		||||
    def getinicfg(self, source: str) -> SectionWrapper:
 | 
			
		||||
        """See :meth:`Pytester.getinicfg`."""
 | 
			
		||||
        return self._pytester.getinicfg(source)
 | 
			
		||||
 | 
			
		||||
    def makepyprojecttoml(self, source) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makepyprojecttoml`."""
 | 
			
		||||
        return legacy_path(self._pytester.makepyprojecttoml(source))
 | 
			
		||||
 | 
			
		||||
    def makepyfile(self, *args, **kwargs) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.makepyfile`."""
 | 
			
		||||
        return legacy_path(self._pytester.makepyfile(*args, **kwargs))
 | 
			
		||||
 | 
			
		||||
    def maketxtfile(self, *args, **kwargs) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.maketxtfile`."""
 | 
			
		||||
        return legacy_path(self._pytester.maketxtfile(*args, **kwargs))
 | 
			
		||||
 | 
			
		||||
    def syspathinsert(self, path=None) -> None:
 | 
			
		||||
        """See :meth:`Pytester.syspathinsert`."""
 | 
			
		||||
        return self._pytester.syspathinsert(path)
 | 
			
		||||
 | 
			
		||||
    def mkdir(self, name) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.mkdir`."""
 | 
			
		||||
        return legacy_path(self._pytester.mkdir(name))
 | 
			
		||||
 | 
			
		||||
    def mkpydir(self, name) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.mkpydir`."""
 | 
			
		||||
        return legacy_path(self._pytester.mkpydir(name))
 | 
			
		||||
 | 
			
		||||
    def copy_example(self, name=None) -> LEGACY_PATH:
 | 
			
		||||
        """See :meth:`Pytester.copy_example`."""
 | 
			
		||||
        return legacy_path(self._pytester.copy_example(name))
 | 
			
		||||
 | 
			
		||||
    def getnode(self, config: Config, arg) -> Optional[Union[Item, Collector]]:
 | 
			
		||||
        """See :meth:`Pytester.getnode`."""
 | 
			
		||||
        return self._pytester.getnode(config, arg)
 | 
			
		||||
 | 
			
		||||
    def getpathnode(self, path):
 | 
			
		||||
        """See :meth:`Pytester.getpathnode`."""
 | 
			
		||||
        return self._pytester.getpathnode(path)
 | 
			
		||||
 | 
			
		||||
    def genitems(self, colitems: List[Union[Item, Collector]]) -> List[Item]:
 | 
			
		||||
        """See :meth:`Pytester.genitems`."""
 | 
			
		||||
        return self._pytester.genitems(colitems)
 | 
			
		||||
 | 
			
		||||
    def runitem(self, source):
 | 
			
		||||
        """See :meth:`Pytester.runitem`."""
 | 
			
		||||
        return self._pytester.runitem(source)
 | 
			
		||||
 | 
			
		||||
    def inline_runsource(self, source, *cmdlineargs):
 | 
			
		||||
        """See :meth:`Pytester.inline_runsource`."""
 | 
			
		||||
        return self._pytester.inline_runsource(source, *cmdlineargs)
 | 
			
		||||
 | 
			
		||||
    def inline_genitems(self, *args):
 | 
			
		||||
        """See :meth:`Pytester.inline_genitems`."""
 | 
			
		||||
        return self._pytester.inline_genitems(*args)
 | 
			
		||||
 | 
			
		||||
    def inline_run(self, *args, plugins=(), no_reraise_ctrlc: bool = False):
 | 
			
		||||
        """See :meth:`Pytester.inline_run`."""
 | 
			
		||||
        return self._pytester.inline_run(
 | 
			
		||||
            *args, plugins=plugins, no_reraise_ctrlc=no_reraise_ctrlc
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def runpytest_inprocess(self, *args, **kwargs) -> RunResult:
 | 
			
		||||
        """See :meth:`Pytester.runpytest_inprocess`."""
 | 
			
		||||
        return self._pytester.runpytest_inprocess(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def runpytest(self, *args, **kwargs) -> RunResult:
 | 
			
		||||
        """See :meth:`Pytester.runpytest`."""
 | 
			
		||||
        return self._pytester.runpytest(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def parseconfig(self, *args) -> Config:
 | 
			
		||||
        """See :meth:`Pytester.parseconfig`."""
 | 
			
		||||
        return self._pytester.parseconfig(*args)
 | 
			
		||||
 | 
			
		||||
    def parseconfigure(self, *args) -> Config:
 | 
			
		||||
        """See :meth:`Pytester.parseconfigure`."""
 | 
			
		||||
        return self._pytester.parseconfigure(*args)
 | 
			
		||||
 | 
			
		||||
    def getitem(self, source, funcname="test_func"):
 | 
			
		||||
        """See :meth:`Pytester.getitem`."""
 | 
			
		||||
        return self._pytester.getitem(source, funcname)
 | 
			
		||||
 | 
			
		||||
    def getitems(self, source):
 | 
			
		||||
        """See :meth:`Pytester.getitems`."""
 | 
			
		||||
        return self._pytester.getitems(source)
 | 
			
		||||
 | 
			
		||||
    def getmodulecol(self, source, configargs=(), withinit=False):
 | 
			
		||||
        """See :meth:`Pytester.getmodulecol`."""
 | 
			
		||||
        return self._pytester.getmodulecol(
 | 
			
		||||
            source, configargs=configargs, withinit=withinit
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def collect_by_name(
 | 
			
		||||
        self, modcol: Collector, name: str
 | 
			
		||||
    ) -> Optional[Union[Item, Collector]]:
 | 
			
		||||
        """See :meth:`Pytester.collect_by_name`."""
 | 
			
		||||
        return self._pytester.collect_by_name(modcol, name)
 | 
			
		||||
 | 
			
		||||
    def popen(
 | 
			
		||||
        self,
 | 
			
		||||
        cmdargs,
 | 
			
		||||
        stdout=subprocess.PIPE,
 | 
			
		||||
        stderr=subprocess.PIPE,
 | 
			
		||||
        stdin=CLOSE_STDIN,
 | 
			
		||||
        **kw,
 | 
			
		||||
    ):
 | 
			
		||||
        """See :meth:`Pytester.popen`."""
 | 
			
		||||
        return self._pytester.popen(cmdargs, stdout, stderr, stdin, **kw)
 | 
			
		||||
 | 
			
		||||
    def run(self, *cmdargs, timeout=None, stdin=CLOSE_STDIN) -> RunResult:
 | 
			
		||||
        """See :meth:`Pytester.run`."""
 | 
			
		||||
        return self._pytester.run(*cmdargs, timeout=timeout, stdin=stdin)
 | 
			
		||||
 | 
			
		||||
    def runpython(self, script) -> RunResult:
 | 
			
		||||
        """See :meth:`Pytester.runpython`."""
 | 
			
		||||
        return self._pytester.runpython(script)
 | 
			
		||||
 | 
			
		||||
    def runpython_c(self, command):
 | 
			
		||||
        """See :meth:`Pytester.runpython_c`."""
 | 
			
		||||
        return self._pytester.runpython_c(command)
 | 
			
		||||
 | 
			
		||||
    def runpytest_subprocess(self, *args, timeout=None) -> RunResult:
 | 
			
		||||
        """See :meth:`Pytester.runpytest_subprocess`."""
 | 
			
		||||
        return self._pytester.runpytest_subprocess(*args, timeout=timeout)
 | 
			
		||||
 | 
			
		||||
    def spawn_pytest(
 | 
			
		||||
        self, string: str, expect_timeout: float = 10.0
 | 
			
		||||
    ) -> "pexpect.spawn":
 | 
			
		||||
        """See :meth:`Pytester.spawn_pytest`."""
 | 
			
		||||
        return self._pytester.spawn_pytest(string, expect_timeout=expect_timeout)
 | 
			
		||||
 | 
			
		||||
    def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn":
 | 
			
		||||
        """See :meth:`Pytester.spawn`."""
 | 
			
		||||
        return self._pytester.spawn(cmd, expect_timeout=expect_timeout)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self) -> str:
 | 
			
		||||
        return f"<Testdir {self.tmpdir!r}>"
 | 
			
		||||
 | 
			
		||||
    def __str__(self) -> str:
 | 
			
		||||
        return str(self.tmpdir)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@final
 | 
			
		||||
class LineMatcher:
 | 
			
		||||
    """Flexible matching of text.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,8 +37,6 @@ from _pytest._code import ExceptionInfo
 | 
			
		|||
from _pytest._code.code import ExceptionRepr
 | 
			
		||||
from _pytest._io.wcwidth import wcswidth
 | 
			
		||||
from _pytest.compat import final
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.compat import legacy_path
 | 
			
		||||
from _pytest.config import _PluggyPlugin
 | 
			
		||||
from _pytest.config import Config
 | 
			
		||||
from _pytest.config import ExitCode
 | 
			
		||||
| 
						 | 
				
			
			@ -383,16 +381,6 @@ class TerminalReporter:
 | 
			
		|||
    def showlongtestinfo(self) -> bool:
 | 
			
		||||
        return self.verbosity > 0
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def startdir(self) -> LEGACY_PATH:
 | 
			
		||||
        """The directory from which pytest was invoked.
 | 
			
		||||
 | 
			
		||||
        Prefer to use ``startpath`` which is a :class:`pathlib.Path`.
 | 
			
		||||
 | 
			
		||||
        :type: LEGACY_PATH
 | 
			
		||||
        """
 | 
			
		||||
        return legacy_path(self.startpath)
 | 
			
		||||
 | 
			
		||||
    def hasopt(self, char: str) -> bool:
 | 
			
		||||
        char = {"xfailed": "x", "skipped": "s"}.get(char, char)
 | 
			
		||||
        return char in self.reportchars
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,8 +13,6 @@ from .pathlib import make_numbered_dir
 | 
			
		|||
from .pathlib import make_numbered_dir_with_cleanup
 | 
			
		||||
from .pathlib import rm_rf
 | 
			
		||||
from _pytest.compat import final
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.compat import legacy_path
 | 
			
		||||
from _pytest.config import Config
 | 
			
		||||
from _pytest.deprecated import check_ispytest
 | 
			
		||||
from _pytest.fixtures import fixture
 | 
			
		||||
| 
						 | 
				
			
			@ -157,29 +155,6 @@ class TempPathFactory:
 | 
			
		|||
        return basetemp
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@final
 | 
			
		||||
@attr.s(init=False, auto_attribs=True)
 | 
			
		||||
class TempdirFactory:
 | 
			
		||||
    """Backward compatibility wrapper that implements :class:``_pytest.compat.LEGACY_PATH``
 | 
			
		||||
    for :class:``TempPathFactory``."""
 | 
			
		||||
 | 
			
		||||
    _tmppath_factory: TempPathFactory
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self, tmppath_factory: TempPathFactory, *, _ispytest: bool = False
 | 
			
		||||
    ) -> None:
 | 
			
		||||
        check_ispytest(_ispytest)
 | 
			
		||||
        self._tmppath_factory = tmppath_factory
 | 
			
		||||
 | 
			
		||||
    def mktemp(self, basename: str, numbered: bool = True) -> LEGACY_PATH:
 | 
			
		||||
        """Same as :meth:`TempPathFactory.mktemp`, but returns a ``_pytest.compat.LEGACY_PATH`` object."""
 | 
			
		||||
        return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve())
 | 
			
		||||
 | 
			
		||||
    def getbasetemp(self) -> LEGACY_PATH:
 | 
			
		||||
        """Backward compat wrapper for ``_tmppath_factory.getbasetemp``."""
 | 
			
		||||
        return legacy_path(self._tmppath_factory.getbasetemp().resolve())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_user() -> Optional[str]:
 | 
			
		||||
    """Return the current user name, or None if getuser() does not work
 | 
			
		||||
    in the current environment (see #1010)."""
 | 
			
		||||
| 
						 | 
				
			
			@ -201,16 +176,7 @@ def pytest_configure(config: Config) -> None:
 | 
			
		|||
    mp = MonkeyPatch()
 | 
			
		||||
    config.add_cleanup(mp.undo)
 | 
			
		||||
    _tmp_path_factory = TempPathFactory.from_config(config, _ispytest=True)
 | 
			
		||||
    _tmpdirhandler = TempdirFactory(_tmp_path_factory, _ispytest=True)
 | 
			
		||||
    mp.setattr(config, "_tmp_path_factory", _tmp_path_factory, raising=False)
 | 
			
		||||
    mp.setattr(config, "_tmpdirhandler", _tmpdirhandler, raising=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@fixture(scope="session")
 | 
			
		||||
def tmpdir_factory(request: FixtureRequest) -> TempdirFactory:
 | 
			
		||||
    """Return a :class:`pytest.TempdirFactory` instance for the test session."""
 | 
			
		||||
    # Set dynamically by pytest_configure() above.
 | 
			
		||||
    return request.config._tmpdirhandler  # type: ignore
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@fixture(scope="session")
 | 
			
		||||
| 
						 | 
				
			
			@ -228,24 +194,6 @@ def _mk_tmp(request: FixtureRequest, factory: TempPathFactory) -> Path:
 | 
			
		|||
    return factory.mktemp(name, numbered=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@fixture
 | 
			
		||||
def tmpdir(tmp_path: Path) -> LEGACY_PATH:
 | 
			
		||||
    """Return a temporary directory path object which is unique to each test
 | 
			
		||||
    function invocation, created as a sub directory of the base temporary
 | 
			
		||||
    directory.
 | 
			
		||||
 | 
			
		||||
    By default, a new base temporary directory is created each test session,
 | 
			
		||||
    and old bases are removed after 3 sessions, to aid in debugging. If
 | 
			
		||||
    ``--basetemp`` is used then it is cleared each session. See :ref:`base
 | 
			
		||||
    temporary directory`.
 | 
			
		||||
 | 
			
		||||
    The returned object is a `legacy_path`_ object.
 | 
			
		||||
 | 
			
		||||
    .. _legacy_path: https://py.readthedocs.io/en/latest/path.html
 | 
			
		||||
    """
 | 
			
		||||
    return legacy_path(tmp_path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@fixture
 | 
			
		||||
def tmp_path(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> Path:
 | 
			
		||||
    """Return a temporary directory path object which is unique to each test
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,6 @@ from _pytest.pytester import LineMatcher
 | 
			
		|||
from _pytest.pytester import Pytester
 | 
			
		||||
from _pytest.pytester import RecordedHookCall
 | 
			
		||||
from _pytest.pytester import RunResult
 | 
			
		||||
from _pytest.pytester import Testdir
 | 
			
		||||
from _pytest.python import Class
 | 
			
		||||
from _pytest.python import Function
 | 
			
		||||
from _pytest.python import Instance
 | 
			
		||||
| 
						 | 
				
			
			@ -61,7 +60,6 @@ from _pytest.recwarn import warns
 | 
			
		|||
from _pytest.runner import CallInfo
 | 
			
		||||
from _pytest.stash import Stash
 | 
			
		||||
from _pytest.stash import StashKey
 | 
			
		||||
from _pytest.tmpdir import TempdirFactory
 | 
			
		||||
from _pytest.tmpdir import TempPathFactory
 | 
			
		||||
from _pytest.warning_types import PytestAssertRewriteWarning
 | 
			
		||||
from _pytest.warning_types import PytestCacheWarning
 | 
			
		||||
| 
						 | 
				
			
			@ -145,8 +143,6 @@ __all__ = [
 | 
			
		|||
    "StashKey",
 | 
			
		||||
    "version_tuple",
 | 
			
		||||
    "TempPathFactory",
 | 
			
		||||
    "Testdir",
 | 
			
		||||
    "TempdirFactory",
 | 
			
		||||
    "UsageError",
 | 
			
		||||
    "WarningsRecorder",
 | 
			
		||||
    "warns",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -967,7 +967,6 @@ class TestRequestBasic:
 | 
			
		|||
        (item,) = pytester.genitems([modcol])
 | 
			
		||||
        req = fixtures.FixtureRequest(item, _ispytest=True)
 | 
			
		||||
        assert req.path == modcol.path
 | 
			
		||||
        assert req.fspath == modcol.fspath
 | 
			
		||||
 | 
			
		||||
    def test_request_fixturenames(self, pytester: Pytester) -> None:
 | 
			
		||||
        pytester.makepyfile(
 | 
			
		||||
| 
						 | 
				
			
			@ -1098,12 +1097,11 @@ class TestRequestSessionScoped:
 | 
			
		|||
    def session_request(self, request):
 | 
			
		||||
        return request
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize("name", ["path", "fspath", "module"])
 | 
			
		||||
    @pytest.mark.parametrize("name", ["path", "module"])
 | 
			
		||||
    def test_session_scoped_unavailable_attributes(self, session_request, name):
 | 
			
		||||
        expected = "path" if name == "fspath" else name
 | 
			
		||||
        with pytest.raises(
 | 
			
		||||
            AttributeError,
 | 
			
		||||
            match=f"{expected} not available in session-scoped context",
 | 
			
		||||
            match=f"{name} not available in session-scoped context",
 | 
			
		||||
        ):
 | 
			
		||||
            getattr(session_request, name)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -614,7 +614,6 @@ class TestSession:
 | 
			
		|||
        items2, hookrec = pytester.inline_genitems(item.nodeid)
 | 
			
		||||
        (item2,) = items2
 | 
			
		||||
        assert item2.name == item.name
 | 
			
		||||
        assert item2.fspath == item.fspath
 | 
			
		||||
        assert item2.path == item.path
 | 
			
		||||
 | 
			
		||||
    def test_find_byid_without_instance_parents(self, pytester: Pytester) -> None:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -635,14 +635,11 @@ class TestConfigAPI:
 | 
			
		|||
        pytest.raises(ValueError, config.getini, "other")
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize("config_type", ["ini", "pyproject"])
 | 
			
		||||
    @pytest.mark.parametrize("ini_type", ["paths", "pathlist"])
 | 
			
		||||
    def test_addini_paths(
 | 
			
		||||
        self, pytester: Pytester, config_type: str, ini_type: str
 | 
			
		||||
    ) -> None:
 | 
			
		||||
    def test_addini_paths(self, pytester: Pytester, config_type: str) -> None:
 | 
			
		||||
        pytester.makeconftest(
 | 
			
		||||
            f"""
 | 
			
		||||
            """
 | 
			
		||||
            def pytest_addoption(parser):
 | 
			
		||||
                parser.addini("paths", "my new ini value", type="{ini_type}")
 | 
			
		||||
                parser.addini("paths", "my new ini value", type="paths")
 | 
			
		||||
                parser.addini("abc", "abc value")
 | 
			
		||||
        """
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -1521,12 +1518,11 @@ class TestOverrideIniArgs:
 | 
			
		|||
        assert result.ret == 0
 | 
			
		||||
        result.stdout.fnmatch_lines(["custom_option:3.0"])
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize("ini_type", ["paths", "pathlist"])
 | 
			
		||||
    def test_override_ini_paths(self, pytester: Pytester, ini_type: str) -> None:
 | 
			
		||||
    def test_override_ini_paths(self, pytester: Pytester) -> None:
 | 
			
		||||
        pytester.makeconftest(
 | 
			
		||||
            f"""
 | 
			
		||||
            """
 | 
			
		||||
            def pytest_addoption(parser):
 | 
			
		||||
                parser.addini("paths", "my new ini value", type="{ini_type}")"""
 | 
			
		||||
                parser.addini("paths", "my new ini value", type="paths")"""
 | 
			
		||||
        )
 | 
			
		||||
        pytester.makeini(
 | 
			
		||||
            """
 | 
			
		||||
| 
						 | 
				
			
			@ -1534,14 +1530,11 @@ class TestOverrideIniArgs:
 | 
			
		|||
            paths=blah.py"""
 | 
			
		||||
        )
 | 
			
		||||
        pytester.makepyfile(
 | 
			
		||||
            rf"""
 | 
			
		||||
            r"""
 | 
			
		||||
            def test_overriden(pytestconfig):
 | 
			
		||||
                config_paths = pytestconfig.getini("paths")
 | 
			
		||||
                print(config_paths)
 | 
			
		||||
                for cpf in config_paths:
 | 
			
		||||
                    if "{ini_type}" == "pathlist":
 | 
			
		||||
                        print('\nuser_path:%s' % cpf.basename)
 | 
			
		||||
                    else:
 | 
			
		||||
                    print('\nuser_path:%s' % cpf.name)
 | 
			
		||||
            """
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,163 @@
 | 
			
		|||
from pathlib import Path
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
from _pytest.compat import LEGACY_PATH
 | 
			
		||||
from _pytest.legacypath import TempdirFactory
 | 
			
		||||
from _pytest.legacypath import Testdir
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_item_fspath(pytester: pytest.Pytester) -> None:
 | 
			
		||||
    pytester.makepyfile("def test_func(): pass")
 | 
			
		||||
    items, hookrec = pytester.inline_genitems()
 | 
			
		||||
    assert len(items) == 1
 | 
			
		||||
    (item,) = items
 | 
			
		||||
    items2, hookrec = pytester.inline_genitems(item.nodeid)
 | 
			
		||||
    (item2,) = items2
 | 
			
		||||
    assert item2.name == item.name
 | 
			
		||||
    assert item2.fspath == item.fspath  # type: ignore[attr-defined]
 | 
			
		||||
    assert item2.path == item.path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_testdir_testtmproot(testdir: Testdir) -> None:
 | 
			
		||||
    """Check test_tmproot is a py.path attribute for backward compatibility."""
 | 
			
		||||
    assert testdir.test_tmproot.check(dir=1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_testdir_makefile_dot_prefixes_extension_silently(
 | 
			
		||||
    testdir: Testdir,
 | 
			
		||||
) -> None:
 | 
			
		||||
    """For backwards compat #8192"""
 | 
			
		||||
    p1 = testdir.makefile("foo.bar", "")
 | 
			
		||||
    assert ".foo.bar" in str(p1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_testdir_makefile_ext_none_raises_type_error(testdir: Testdir) -> None:
 | 
			
		||||
    """For backwards compat #8192"""
 | 
			
		||||
    with pytest.raises(TypeError):
 | 
			
		||||
        testdir.makefile(None, "")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_testdir_makefile_ext_empty_string_makes_file(testdir: Testdir) -> None:
 | 
			
		||||
    """For backwards compat #8192"""
 | 
			
		||||
    p1 = testdir.makefile("", "")
 | 
			
		||||
    assert "test_testdir_makefile" in str(p1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def attempt_symlink_to(path: str, to_path: str) -> None:
 | 
			
		||||
    """Try to make a symlink from "path" to "to_path", skipping in case this platform
 | 
			
		||||
    does not support it or we don't have sufficient privileges (common on Windows)."""
 | 
			
		||||
    try:
 | 
			
		||||
        Path(path).symlink_to(Path(to_path))
 | 
			
		||||
    except OSError:
 | 
			
		||||
        pytest.skip("could not create symbolic link")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_tmpdir_factory(
 | 
			
		||||
    tmpdir_factory: TempdirFactory,
 | 
			
		||||
    tmp_path_factory: pytest.TempPathFactory,
 | 
			
		||||
) -> None:
 | 
			
		||||
    assert str(tmpdir_factory.getbasetemp()) == str(tmp_path_factory.getbasetemp())
 | 
			
		||||
    dir = tmpdir_factory.mktemp("foo")
 | 
			
		||||
    assert dir.exists()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_tmpdir_equals_tmp_path(tmpdir: LEGACY_PATH, tmp_path: Path) -> None:
 | 
			
		||||
    assert Path(tmpdir) == tmp_path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_tmpdir_always_is_realpath(pytester: pytest.Pytester) -> None:
 | 
			
		||||
    # See test_tmp_path_always_is_realpath.
 | 
			
		||||
    realtemp = pytester.mkdir("myrealtemp")
 | 
			
		||||
    linktemp = pytester.path.joinpath("symlinktemp")
 | 
			
		||||
    attempt_symlink_to(str(linktemp), str(realtemp))
 | 
			
		||||
    p = pytester.makepyfile(
 | 
			
		||||
        """
 | 
			
		||||
        def test_1(tmpdir):
 | 
			
		||||
            import os
 | 
			
		||||
            assert os.path.realpath(str(tmpdir)) == str(tmpdir)
 | 
			
		||||
    """
 | 
			
		||||
    )
 | 
			
		||||
    result = pytester.runpytest("-s", p, "--basetemp=%s/bt" % linktemp)
 | 
			
		||||
    assert not result.ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_cache_makedir(cache: pytest.Cache) -> None:
 | 
			
		||||
    dir = cache.makedir("foo")  # type: ignore[attr-defined]
 | 
			
		||||
    assert dir.exists()
 | 
			
		||||
    dir.remove()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_fixturerequest_getmodulepath(pytester: pytest.Pytester) -> None:
 | 
			
		||||
    modcol = pytester.getmodulecol("def test_somefunc(): pass")
 | 
			
		||||
    (item,) = pytester.genitems([modcol])
 | 
			
		||||
    req = pytest.FixtureRequest(item, _ispytest=True)
 | 
			
		||||
    assert req.path == modcol.path
 | 
			
		||||
    assert req.fspath == modcol.fspath  # type: ignore[attr-defined]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestFixtureRequestSessionScoped:
 | 
			
		||||
    @pytest.fixture(scope="session")
 | 
			
		||||
    def session_request(self, request):
 | 
			
		||||
        return request
 | 
			
		||||
 | 
			
		||||
    def test_session_scoped_unavailable_attributes(self, session_request):
 | 
			
		||||
        with pytest.raises(
 | 
			
		||||
            AttributeError,
 | 
			
		||||
            match="path not available in session-scoped context",
 | 
			
		||||
        ):
 | 
			
		||||
            session_request.fspath
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize("config_type", ["ini", "pyproject"])
 | 
			
		||||
def test_addini_paths(pytester: pytest.Pytester, config_type: str) -> None:
 | 
			
		||||
    pytester.makeconftest(
 | 
			
		||||
        """
 | 
			
		||||
        def pytest_addoption(parser):
 | 
			
		||||
            parser.addini("paths", "my new ini value", type="pathlist")
 | 
			
		||||
            parser.addini("abc", "abc value")
 | 
			
		||||
    """
 | 
			
		||||
    )
 | 
			
		||||
    if config_type == "ini":
 | 
			
		||||
        inipath = pytester.makeini(
 | 
			
		||||
            """
 | 
			
		||||
            [pytest]
 | 
			
		||||
            paths=hello world/sub.py
 | 
			
		||||
        """
 | 
			
		||||
        )
 | 
			
		||||
    elif config_type == "pyproject":
 | 
			
		||||
        inipath = pytester.makepyprojecttoml(
 | 
			
		||||
            """
 | 
			
		||||
            [tool.pytest.ini_options]
 | 
			
		||||
            paths=["hello", "world/sub.py"]
 | 
			
		||||
        """
 | 
			
		||||
        )
 | 
			
		||||
    config = pytester.parseconfig()
 | 
			
		||||
    values = config.getini("paths")
 | 
			
		||||
    assert len(values) == 2
 | 
			
		||||
    assert values[0] == inipath.parent.joinpath("hello")
 | 
			
		||||
    assert values[1] == inipath.parent.joinpath("world/sub.py")
 | 
			
		||||
    pytest.raises(ValueError, config.getini, "other")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_override_ini_paths(pytester: pytest.Pytester) -> None:
 | 
			
		||||
    pytester.makeconftest(
 | 
			
		||||
        """
 | 
			
		||||
        def pytest_addoption(parser):
 | 
			
		||||
            parser.addini("paths", "my new ini value", type="pathlist")"""
 | 
			
		||||
    )
 | 
			
		||||
    pytester.makeini(
 | 
			
		||||
        """
 | 
			
		||||
        [pytest]
 | 
			
		||||
        paths=blah.py"""
 | 
			
		||||
    )
 | 
			
		||||
    pytester.makepyfile(
 | 
			
		||||
        r"""
 | 
			
		||||
        def test_overriden(pytestconfig):
 | 
			
		||||
            config_paths = pytestconfig.getini("paths")
 | 
			
		||||
            print(config_paths)
 | 
			
		||||
            for cpf in config_paths:
 | 
			
		||||
                print('\nuser_path:%s' % cpf.basename)
 | 
			
		||||
        """
 | 
			
		||||
    )
 | 
			
		||||
    result = pytester.runpytest("--override-ini", "paths=foo/bar1.py foo/bar2.py", "-s")
 | 
			
		||||
    result.stdout.fnmatch_lines(["user_path:bar1.py", "user_path:bar2.py"])
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,6 @@ from _pytest.pytester import LineMatcher
 | 
			
		|||
from _pytest.pytester import Pytester
 | 
			
		||||
from _pytest.pytester import SysModulesSnapshot
 | 
			
		||||
from _pytest.pytester import SysPathsSnapshot
 | 
			
		||||
from _pytest.pytester import Testdir
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_make_hook_recorder(pytester: Pytester) -> None:
 | 
			
		||||
| 
						 | 
				
			
			@ -814,19 +813,6 @@ def test_makefile_joins_absolute_path(pytester: Pytester) -> None:
 | 
			
		|||
    assert str(p1) == str(pytester.path / "absfile.py")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_testtmproot(testdir) -> None:
 | 
			
		||||
    """Check test_tmproot is a py.path attribute for backward compatibility."""
 | 
			
		||||
    assert testdir.test_tmproot.check(dir=1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_testdir_makefile_dot_prefixes_extension_silently(
 | 
			
		||||
    testdir: Testdir,
 | 
			
		||||
) -> None:
 | 
			
		||||
    """For backwards compat #8192"""
 | 
			
		||||
    p1 = testdir.makefile("foo.bar", "")
 | 
			
		||||
    assert ".foo.bar" in str(p1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_pytester_makefile_dot_prefixes_extension_with_warning(
 | 
			
		||||
    pytester: Pytester,
 | 
			
		||||
) -> None:
 | 
			
		||||
| 
						 | 
				
			
			@ -837,18 +823,6 @@ def test_pytester_makefile_dot_prefixes_extension_with_warning(
 | 
			
		|||
        pytester.makefile("foo.bar", "")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_testdir_makefile_ext_none_raises_type_error(testdir) -> None:
 | 
			
		||||
    """For backwards compat #8192"""
 | 
			
		||||
    with pytest.raises(TypeError):
 | 
			
		||||
        testdir.makefile(None, "")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_testdir_makefile_ext_empty_string_makes_file(testdir) -> None:
 | 
			
		||||
    """For backwards compat #8192"""
 | 
			
		||||
    p1 = testdir.makefile("", "")
 | 
			
		||||
    assert "test_testdir_makefile" in str(p1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.filterwarnings("default")
 | 
			
		||||
def test_pytester_assert_outcomes_warnings(pytester: Pytester) -> None:
 | 
			
		||||
    pytester.makepyfile(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,8 +118,8 @@ def test_mktemp(pytester: Pytester, basename: str, is_ok: bool) -> None:
 | 
			
		|||
        result.stdout.fnmatch_lines("*ValueError*")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_tmpdir_always_is_realpath(pytester: Pytester) -> None:
 | 
			
		||||
    # the reason why tmpdir should be a realpath is that
 | 
			
		||||
def test_tmp_path_always_is_realpath(pytester: Pytester, monkeypatch) -> None:
 | 
			
		||||
    # the reason why tmp_path should be a realpath is that
 | 
			
		||||
    # when you cd to it and do "os.getcwd()" you will anyway
 | 
			
		||||
    # get the realpath.  Using the symlinked path can thus
 | 
			
		||||
    # easily result in path-inequality
 | 
			
		||||
| 
						 | 
				
			
			@ -128,22 +128,6 @@ def test_tmpdir_always_is_realpath(pytester: Pytester) -> None:
 | 
			
		|||
    realtemp = pytester.mkdir("myrealtemp")
 | 
			
		||||
    linktemp = pytester.path.joinpath("symlinktemp")
 | 
			
		||||
    attempt_symlink_to(linktemp, str(realtemp))
 | 
			
		||||
    p = pytester.makepyfile(
 | 
			
		||||
        """
 | 
			
		||||
        def test_1(tmpdir):
 | 
			
		||||
            import os
 | 
			
		||||
            assert os.path.realpath(str(tmpdir)) == str(tmpdir)
 | 
			
		||||
    """
 | 
			
		||||
    )
 | 
			
		||||
    result = pytester.runpytest("-s", p, "--basetemp=%s/bt" % linktemp)
 | 
			
		||||
    assert not result.ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_tmp_path_always_is_realpath(pytester: Pytester, monkeypatch) -> None:
 | 
			
		||||
    # for reasoning see: test_tmpdir_always_is_realpath test-case
 | 
			
		||||
    realtemp = pytester.mkdir("myrealtemp")
 | 
			
		||||
    linktemp = pytester.path.joinpath("symlinktemp")
 | 
			
		||||
    attempt_symlink_to(linktemp, str(realtemp))
 | 
			
		||||
    monkeypatch.setenv("PYTEST_DEBUG_TEMPROOT", str(linktemp))
 | 
			
		||||
    pytester.makepyfile(
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -423,10 +407,6 @@ def attempt_symlink_to(path, to_path):
 | 
			
		|||
        pytest.skip("could not create symbolic link")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_tmpdir_equals_tmp_path(tmpdir, tmp_path):
 | 
			
		||||
    assert Path(tmpdir) == tmp_path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_basetemp_with_read_only_files(pytester: Pytester) -> None:
 | 
			
		||||
    """Integration test for #5524"""
 | 
			
		||||
    pytester.makepyfile(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue