晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷。渔人甚异之,复前行,欲穷其林。 林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田、美池、桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。 见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:“不足为外人道也。”(间隔 一作:隔绝) 既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。 南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终。后遂无问津者。
| DIR:/opt/cloudlinux/venv/lib64/python3.11/site-packages/_pytest/ |
| Current File : //opt/cloudlinux/venv/lib64/python3.11/site-packages/_pytest/legacypath.py |
"""Add backward compatibility support for the legacy py path type."""
import dataclasses
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
from iniconfig import SectionWrapper
from _pytest.cacheprovider import Cache
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 hookimpl
from _pytest.config import PytestPluginManager
from _pytest.deprecated import check_ispytest
from _pytest.fixtures import fixture
from _pytest.fixtures import FixtureRequest
from _pytest.main import Session
from _pytest.monkeypatch import MonkeyPatch
from _pytest.nodes import Collector
from _pytest.nodes import Item
from _pytest.nodes import Node
from _pytest.pytester import HookRecorder
from _pytest.pytester import Pytester
from _pytest.pytester import RunResult
from _pytest.terminal import TerminalReporter
from _pytest.tmpdir import TempPathFactory
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" = 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)
class LegacyTestdirPlugin:
@staticmethod
@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)
@final
@dataclasses.dataclass
class TempdirFactory:
"""Backward compatibility wrapper that implements :class:`py.path.local`
for :class:`TempPathFactory`.
.. note::
These days, it is preferred to use ``tmp_path_factory``.
:ref:`About the tmpdir and tmpdir_factory fixtures<tmpdir and tmpdir_factory>`.
"""
_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 :class:`py.path.local` object."""
return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve())
def getbasetemp(self) -> LEGACY_PATH:
"""Same as :meth:`TempPathFactory.getbasetemp`, but returns a :class:`py.path.local` object."""
return legacy_path(self._tmppath_factory.getbasetemp().resolve())
class LegacyTmpdirPlugin:
@staticmethod
@fixture(scope="session")
def tmpdir_factory(request: FixtureRequest) -> TempdirFactory:
"""Return a :class:`pytest.TempdirFactory` instance for the test session."""
# Set dynamically by pytest_configure().
return request.config._tmpdirhandler # type: ignore
@staticmethod
@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.
.. note::
These days, it is preferred to use ``tmp_path``.
:ref:`About the tmpdir and tmpdir_factory fixtures<tmpdir and tmpdir_factory>`.
.. _legacy_path: https://py.readthedocs.io/en/latest/path.html
"""
return legacy_path(tmp_path)
def Cache_makedir(self: 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: 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: 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: 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: 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: 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)
@hookimpl(tryfirst=True)
def pytest_load_initial_conftests(early_config: Config) -> None:
"""Monkeypatch legacy path attributes in several classes, as early as possible."""
mp = MonkeyPatch()
early_config.add_cleanup(mp.undo)
# Add Cache.makedir().
mp.setattr(Cache, "makedir", Cache_makedir, raising=False)
# Add FixtureRequest.fspath property.
mp.setattr(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(Config, "invocation_dir", property(Config_invocation_dir), raising=False)
mp.setattr(Config, "rootdir", property(Config_rootdir), raising=False)
mp.setattr(Config, "inifile", property(Config_inifile), raising=False)
# Add Session.startdir property.
mp.setattr(Session, "startdir", property(Session_stardir), raising=False)
# Add pathlist configuration type.
mp.setattr(Config, "_getini_unknown_type", Config__getini_unknown_type)
# Add Node.fspath property.
mp.setattr(Node, "fspath", property(Node_fspath, Node_fspath_set), raising=False)
@hookimpl
def pytest_configure(config: Config) -> None:
"""Installs the LegacyTmpdirPlugin if the ``tmpdir`` plugin is also installed."""
if config.pluginmanager.has_plugin("tmpdir"):
mp = MonkeyPatch()
config.add_cleanup(mp.undo)
# 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")
@hookimpl
def pytest_plugin_registered(plugin: object, manager: PytestPluginManager) -> None:
# pytester is not loaded by default and is commonly loaded from a conftest,
# so checking for it in `pytest_configure` is not enough.
is_pytester = plugin is manager.get_plugin("pytester")
if is_pytester and not manager.is_registered(LegacyTestdirPlugin):
manager.register(LegacyTestdirPlugin, "legacypath-pytester")
|