Stop importing `pytest` to avoid upcoming import cycles

Don't import `pytest` from within some `_pytest` modules since an
upcoming commit will import from them into `pytest`.

It would have been nice not to have to do it, so that internal plugins
look more like external plugins, but with the existing layout this seems
unavoidable.
This commit is contained in:
Ran Benita 2020-11-06 19:25:40 +02:00
parent 3bcd316f07
commit 1cbb0c3554
7 changed files with 79 additions and 67 deletions

View File

@ -15,7 +15,6 @@ from typing import Union
import attr import attr
import py import py
import pytest
from .pathlib import resolve_from_str from .pathlib import resolve_from_str
from .pathlib import rm_rf from .pathlib import rm_rf
from .reports import CollectReport from .reports import CollectReport
@ -24,7 +23,9 @@ from _pytest._io import TerminalWriter
from _pytest.compat import final from _pytest.compat import final
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.config import hookimpl
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.fixtures import fixture
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.main import Session from _pytest.main import Session
from _pytest.python import Module from _pytest.python import Module
@ -182,7 +183,7 @@ class LFPluginCollWrapper:
self.lfplugin = lfplugin self.lfplugin = lfplugin
self._collected_at_least_one_failure = False self._collected_at_least_one_failure = False
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_make_collect_report(self, collector: nodes.Collector): def pytest_make_collect_report(self, collector: nodes.Collector):
if isinstance(collector, Session): if isinstance(collector, Session):
out = yield out = yield
@ -229,7 +230,7 @@ class LFPluginCollSkipfiles:
def __init__(self, lfplugin: "LFPlugin") -> None: def __init__(self, lfplugin: "LFPlugin") -> None:
self.lfplugin = lfplugin self.lfplugin = lfplugin
@pytest.hookimpl @hookimpl
def pytest_make_collect_report( def pytest_make_collect_report(
self, collector: nodes.Collector self, collector: nodes.Collector
) -> Optional[CollectReport]: ) -> Optional[CollectReport]:
@ -291,7 +292,7 @@ class LFPlugin:
else: else:
self.lastfailed[report.nodeid] = True self.lastfailed[report.nodeid] = True
@pytest.hookimpl(hookwrapper=True, tryfirst=True) @hookimpl(hookwrapper=True, tryfirst=True)
def pytest_collection_modifyitems( def pytest_collection_modifyitems(
self, config: Config, items: List[nodes.Item] self, config: Config, items: List[nodes.Item]
) -> Generator[None, None, None]: ) -> Generator[None, None, None]:
@ -363,7 +364,7 @@ class NFPlugin:
assert config.cache is not None assert config.cache is not None
self.cached_nodeids = set(config.cache.get("cache/nodeids", [])) self.cached_nodeids = set(config.cache.get("cache/nodeids", []))
@pytest.hookimpl(hookwrapper=True, tryfirst=True) @hookimpl(hookwrapper=True, tryfirst=True)
def pytest_collection_modifyitems( def pytest_collection_modifyitems(
self, items: List[nodes.Item] self, items: List[nodes.Item]
) -> Generator[None, None, None]: ) -> Generator[None, None, None]:
@ -466,14 +467,14 @@ def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]:
return None return None
@pytest.hookimpl(tryfirst=True) @hookimpl(tryfirst=True)
def pytest_configure(config: Config) -> None: def pytest_configure(config: Config) -> None:
config.cache = Cache.for_config(config) config.cache = Cache.for_config(config)
config.pluginmanager.register(LFPlugin(config), "lfplugin") config.pluginmanager.register(LFPlugin(config), "lfplugin")
config.pluginmanager.register(NFPlugin(config), "nfplugin") config.pluginmanager.register(NFPlugin(config), "nfplugin")
@pytest.fixture @fixture
def cache(request: FixtureRequest) -> Cache: def cache(request: FixtureRequest) -> Cache:
"""Return a cache object that can persist state between testing sessions. """Return a cache object that can persist state between testing sessions.

View File

@ -17,12 +17,14 @@ from typing import Tuple
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Union from typing import Union
import pytest
from _pytest.compat import final from _pytest.compat import final
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import hookimpl
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.fixtures import fixture
from _pytest.fixtures import SubRequest from _pytest.fixtures import SubRequest
from _pytest.nodes import Collector from _pytest.nodes import Collector
from _pytest.nodes import File
from _pytest.nodes import Item from _pytest.nodes import Item
if TYPE_CHECKING: if TYPE_CHECKING:
@ -145,7 +147,7 @@ def _py36_windowsconsoleio_workaround(stream: TextIO) -> None:
sys.stderr = _reopen_stdio(sys.stderr, "wb") sys.stderr = _reopen_stdio(sys.stderr, "wb")
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_load_initial_conftests(early_config: Config): def pytest_load_initial_conftests(early_config: Config):
ns = early_config.known_args_namespace ns = early_config.known_args_namespace
if ns.capture == "fd": if ns.capture == "fd":
@ -784,9 +786,9 @@ class CaptureManager:
# Hooks # Hooks
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_make_collect_report(self, collector: Collector): def pytest_make_collect_report(self, collector: Collector):
if isinstance(collector, pytest.File): if isinstance(collector, File):
self.resume_global_capture() self.resume_global_capture()
outcome = yield outcome = yield
self.suspend_global_capture() self.suspend_global_capture()
@ -799,26 +801,26 @@ class CaptureManager:
else: else:
yield yield
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_runtest_setup(self, item: Item) -> Generator[None, None, None]: def pytest_runtest_setup(self, item: Item) -> Generator[None, None, None]:
with self.item_capture("setup", item): with self.item_capture("setup", item):
yield yield
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_runtest_call(self, item: Item) -> Generator[None, None, None]: def pytest_runtest_call(self, item: Item) -> Generator[None, None, None]:
with self.item_capture("call", item): with self.item_capture("call", item):
yield yield
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_runtest_teardown(self, item: Item) -> Generator[None, None, None]: def pytest_runtest_teardown(self, item: Item) -> Generator[None, None, None]:
with self.item_capture("teardown", item): with self.item_capture("teardown", item):
yield yield
@pytest.hookimpl(tryfirst=True) @hookimpl(tryfirst=True)
def pytest_keyboard_interrupt(self) -> None: def pytest_keyboard_interrupt(self) -> None:
self.stop_global_capturing() self.stop_global_capturing()
@pytest.hookimpl(tryfirst=True) @hookimpl(tryfirst=True)
def pytest_internalerror(self) -> None: def pytest_internalerror(self) -> None:
self.stop_global_capturing() self.stop_global_capturing()
@ -893,7 +895,7 @@ class CaptureFixture(Generic[AnyStr]):
# The fixtures. # The fixtures.
@pytest.fixture @fixture
def capsys(request: SubRequest) -> Generator[CaptureFixture[str], None, None]: def capsys(request: SubRequest) -> Generator[CaptureFixture[str], None, None]:
"""Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``. """Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``.
@ -910,7 +912,7 @@ def capsys(request: SubRequest) -> Generator[CaptureFixture[str], None, None]:
capman.unset_fixture() capman.unset_fixture()
@pytest.fixture @fixture
def capsysbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, None]: def capsysbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, None]:
"""Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``. """Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``.
@ -927,7 +929,7 @@ def capsysbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None,
capman.unset_fixture() capman.unset_fixture()
@pytest.fixture @fixture
def capfd(request: SubRequest) -> Generator[CaptureFixture[str], None, None]: def capfd(request: SubRequest) -> Generator[CaptureFixture[str], None, None]:
"""Enable text capturing of writes to file descriptors ``1`` and ``2``. """Enable text capturing of writes to file descriptors ``1`` and ``2``.
@ -944,7 +946,7 @@ def capfd(request: SubRequest) -> Generator[CaptureFixture[str], None, None]:
capman.unset_fixture() capman.unset_fixture()
@pytest.fixture @fixture
def capfdbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, None]: def capfdbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, None]:
"""Enable bytes capturing of writes to file descriptors ``1`` and ``2``. """Enable bytes capturing of writes to file descriptors ``1`` and ``2``.

View File

@ -16,7 +16,6 @@ from typing import Tuple
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
import pytest
from _pytest import nodes from _pytest import nodes
from _pytest._io import TerminalWriter from _pytest._io import TerminalWriter
from _pytest.capture import CaptureManager from _pytest.capture import CaptureManager
@ -25,7 +24,10 @@ from _pytest.compat import nullcontext
from _pytest.config import _strtobool from _pytest.config import _strtobool
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import create_terminal_writer from _pytest.config import create_terminal_writer
from _pytest.config import hookimpl
from _pytest.config import UsageError
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.fixtures import fixture
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.main import Session from _pytest.main import Session
from _pytest.store import StoreKey from _pytest.store import StoreKey
@ -468,7 +470,7 @@ class LogCaptureFixture:
self.handler.setLevel(handler_orig_level) self.handler.setLevel(handler_orig_level)
@pytest.fixture @fixture
def caplog(request: FixtureRequest) -> Generator[LogCaptureFixture, None, None]: def caplog(request: FixtureRequest) -> Generator[LogCaptureFixture, None, None]:
"""Access and control log capturing. """Access and control log capturing.
@ -501,7 +503,7 @@ def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[i
return int(getattr(logging, log_level, log_level)) return int(getattr(logging, log_level, log_level))
except ValueError as e: except ValueError as e:
# Python logging does not recognise this as a logging level # Python logging does not recognise this as a logging level
raise pytest.UsageError( raise UsageError(
"'{}' is not recognized as a logging level name for " "'{}' is not recognized as a logging level name for "
"'{}'. Please consider passing the " "'{}'. Please consider passing the "
"logging level num instead.".format(log_level, setting_name) "logging level num instead.".format(log_level, setting_name)
@ -509,7 +511,7 @@ def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[i
# run after terminalreporter/capturemanager are configured # run after terminalreporter/capturemanager are configured
@pytest.hookimpl(trylast=True) @hookimpl(trylast=True)
def pytest_configure(config: Config) -> None: def pytest_configure(config: Config) -> None:
config.pluginmanager.register(LoggingPlugin(config), "logging-plugin") config.pluginmanager.register(LoggingPlugin(config), "logging-plugin")
@ -639,7 +641,7 @@ class LoggingPlugin:
return True return True
@pytest.hookimpl(hookwrapper=True, tryfirst=True) @hookimpl(hookwrapper=True, tryfirst=True)
def pytest_sessionstart(self) -> Generator[None, None, None]: def pytest_sessionstart(self) -> Generator[None, None, None]:
self.log_cli_handler.set_when("sessionstart") self.log_cli_handler.set_when("sessionstart")
@ -647,7 +649,7 @@ class LoggingPlugin:
with catching_logs(self.log_file_handler, level=self.log_file_level): with catching_logs(self.log_file_handler, level=self.log_file_level):
yield yield
@pytest.hookimpl(hookwrapper=True, tryfirst=True) @hookimpl(hookwrapper=True, tryfirst=True)
def pytest_collection(self) -> Generator[None, None, None]: def pytest_collection(self) -> Generator[None, None, None]:
self.log_cli_handler.set_when("collection") self.log_cli_handler.set_when("collection")
@ -655,7 +657,7 @@ class LoggingPlugin:
with catching_logs(self.log_file_handler, level=self.log_file_level): with catching_logs(self.log_file_handler, level=self.log_file_level):
yield yield
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_runtestloop(self, session: Session) -> Generator[None, None, None]: def pytest_runtestloop(self, session: Session) -> Generator[None, None, None]:
if session.config.option.collectonly: if session.config.option.collectonly:
yield yield
@ -669,12 +671,12 @@ class LoggingPlugin:
with catching_logs(self.log_file_handler, level=self.log_file_level): with catching_logs(self.log_file_handler, level=self.log_file_level):
yield # Run all the tests. yield # Run all the tests.
@pytest.hookimpl @hookimpl
def pytest_runtest_logstart(self) -> None: def pytest_runtest_logstart(self) -> None:
self.log_cli_handler.reset() self.log_cli_handler.reset()
self.log_cli_handler.set_when("start") self.log_cli_handler.set_when("start")
@pytest.hookimpl @hookimpl
def pytest_runtest_logreport(self) -> None: def pytest_runtest_logreport(self) -> None:
self.log_cli_handler.set_when("logreport") self.log_cli_handler.set_when("logreport")
@ -695,7 +697,7 @@ class LoggingPlugin:
log = report_handler.stream.getvalue().strip() log = report_handler.stream.getvalue().strip()
item.add_report_section(when, "log", log) item.add_report_section(when, "log", log)
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]: def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]:
self.log_cli_handler.set_when("setup") self.log_cli_handler.set_when("setup")
@ -703,13 +705,13 @@ class LoggingPlugin:
item._store[caplog_records_key] = empty item._store[caplog_records_key] = empty
yield from self._runtest_for(item, "setup") yield from self._runtest_for(item, "setup")
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_runtest_call(self, item: nodes.Item) -> Generator[None, None, None]: def pytest_runtest_call(self, item: nodes.Item) -> Generator[None, None, None]:
self.log_cli_handler.set_when("call") self.log_cli_handler.set_when("call")
yield from self._runtest_for(item, "call") yield from self._runtest_for(item, "call")
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_runtest_teardown(self, item: nodes.Item) -> Generator[None, None, None]: def pytest_runtest_teardown(self, item: nodes.Item) -> Generator[None, None, None]:
self.log_cli_handler.set_when("teardown") self.log_cli_handler.set_when("teardown")
@ -717,11 +719,11 @@ class LoggingPlugin:
del item._store[caplog_records_key] del item._store[caplog_records_key]
del item._store[caplog_handler_key] del item._store[caplog_handler_key]
@pytest.hookimpl @hookimpl
def pytest_runtest_logfinish(self) -> None: def pytest_runtest_logfinish(self) -> None:
self.log_cli_handler.set_when("finish") self.log_cli_handler.set_when("finish")
@pytest.hookimpl(hookwrapper=True, tryfirst=True) @hookimpl(hookwrapper=True, tryfirst=True)
def pytest_sessionfinish(self) -> Generator[None, None, None]: def pytest_sessionfinish(self) -> Generator[None, None, None]:
self.log_cli_handler.set_when("sessionfinish") self.log_cli_handler.set_when("sessionfinish")
@ -729,7 +731,7 @@ class LoggingPlugin:
with catching_logs(self.log_file_handler, level=self.log_file_level): with catching_logs(self.log_file_handler, level=self.log_file_level):
yield yield
@pytest.hookimpl @hookimpl
def pytest_unconfigure(self) -> None: def pytest_unconfigure(self) -> None:
# Close the FileHandler explicitly. # Close the FileHandler explicitly.
# (logging.shutdown might have lost the weakref?!) # (logging.shutdown might have lost the weakref?!)

View File

@ -15,9 +15,9 @@ from typing import Tuple
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
import pytest
from _pytest.compat import final from _pytest.compat import final
from _pytest.fixtures import fixture from _pytest.fixtures import fixture
from _pytest.warning_types import PytestWarning
RE_IMPORT_ERROR_NAME = re.compile(r"^No module named (.*)$") RE_IMPORT_ERROR_NAME = re.compile(r"^No module named (.*)$")
@ -271,7 +271,7 @@ class MonkeyPatch:
""" """
if not isinstance(value, str): if not isinstance(value, str):
warnings.warn( # type: ignore[unreachable] warnings.warn( # type: ignore[unreachable]
pytest.PytestWarning( PytestWarning(
"Value of environment variable {name} type should be str, but got " "Value of environment variable {name} type should be str, but got "
"{value!r} (type: {type}); converted to str implicitly".format( "{value!r} (type: {type}); converted to str implicitly".format(
name=name, value=value, type=type(value).__name__ name=name, value=value, type=type(value).__name__

View File

@ -34,7 +34,6 @@ import py
from iniconfig import IniConfig from iniconfig import IniConfig
from iniconfig import SectionWrapper from iniconfig import SectionWrapper
import pytest
from _pytest import timing from _pytest import timing
from _pytest._code import Source from _pytest._code import Source
from _pytest.capture import _get_multicapture from _pytest.capture import _get_multicapture
@ -42,17 +41,24 @@ from _pytest.compat import final
from _pytest.config import _PluggyPlugin from _pytest.config import _PluggyPlugin
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.config import hookimpl
from _pytest.config import main
from _pytest.config import PytestPluginManager from _pytest.config import PytestPluginManager
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.fixtures import fixture
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.main import Session from _pytest.main import Session
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
from _pytest.nodes import Collector from _pytest.nodes import Collector
from _pytest.nodes import Item from _pytest.nodes import Item
from _pytest.outcomes import fail
from _pytest.outcomes import importorskip
from _pytest.outcomes import skip
from _pytest.pathlib import make_numbered_dir from _pytest.pathlib import make_numbered_dir
from _pytest.reports import CollectReport from _pytest.reports import CollectReport
from _pytest.reports import TestReport from _pytest.reports import TestReport
from _pytest.tmpdir import TempPathFactory from _pytest.tmpdir import TempPathFactory
from _pytest.warning_types import PytestWarning
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Literal from typing_extensions import Literal
@ -143,7 +149,7 @@ class LsofFdLeakChecker:
else: else:
return True return True
@pytest.hookimpl(hookwrapper=True, tryfirst=True) @hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_protocol(self, item: Item) -> Generator[None, None, None]: def pytest_runtest_protocol(self, item: Item) -> Generator[None, None, None]:
lines1 = self.get_open_files() lines1 = self.get_open_files()
yield yield
@ -165,13 +171,13 @@ class LsofFdLeakChecker:
"*** function %s:%s: %s " % item.location, "*** function %s:%s: %s " % item.location,
"See issue #2366", "See issue #2366",
] ]
item.warn(pytest.PytestWarning("\n".join(error))) item.warn(PytestWarning("\n".join(error)))
# used at least by pytest-xdist plugin # used at least by pytest-xdist plugin
@pytest.fixture @fixture
def _pytest(request: FixtureRequest) -> "PytestArg": def _pytest(request: FixtureRequest) -> "PytestArg":
"""Return a helper which offers a gethookrecorder(hook) method which """Return a helper which offers a gethookrecorder(hook) method which
returns a HookRecorder instance which helps to make assertions about called returns a HookRecorder instance which helps to make assertions about called
@ -257,7 +263,7 @@ class HookRecorder:
break break
print("NONAMEMATCH", name, "with", call) print("NONAMEMATCH", name, "with", call)
else: else:
pytest.fail(f"could not find {name!r} check {check!r}") fail(f"could not find {name!r} check {check!r}")
def popcall(self, name: str) -> ParsedCall: def popcall(self, name: str) -> ParsedCall:
__tracebackhide__ = True __tracebackhide__ = True
@ -267,7 +273,7 @@ class HookRecorder:
return call return call
lines = [f"could not find call {name!r}, in:"] lines = [f"could not find call {name!r}, in:"]
lines.extend([" %s" % x for x in self.calls]) lines.extend([" %s" % x for x in self.calls])
pytest.fail("\n".join(lines)) fail("\n".join(lines))
def getcall(self, name: str) -> ParsedCall: def getcall(self, name: str) -> ParsedCall:
values = self.getcalls(name) values = self.getcalls(name)
@ -417,14 +423,14 @@ class HookRecorder:
self.calls[:] = [] self.calls[:] = []
@pytest.fixture @fixture
def linecomp() -> "LineComp": def linecomp() -> "LineComp":
"""A :class: `LineComp` instance for checking that an input linearly """A :class: `LineComp` instance for checking that an input linearly
contains a sequence of strings.""" contains a sequence of strings."""
return LineComp() return LineComp()
@pytest.fixture(name="LineMatcher") @fixture(name="LineMatcher")
def LineMatcher_fixture(request: FixtureRequest) -> Type["LineMatcher"]: def LineMatcher_fixture(request: FixtureRequest) -> Type["LineMatcher"]:
"""A reference to the :class: `LineMatcher`. """A reference to the :class: `LineMatcher`.
@ -434,7 +440,7 @@ def LineMatcher_fixture(request: FixtureRequest) -> Type["LineMatcher"]:
return LineMatcher return LineMatcher
@pytest.fixture @fixture
def pytester(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> "Pytester": def pytester(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> "Pytester":
""" """
Facilities to write tests/configuration files, execute pytest in isolation, and match Facilities to write tests/configuration files, execute pytest in isolation, and match
@ -449,7 +455,7 @@ def pytester(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> "Pyt
return Pytester(request, tmp_path_factory) return Pytester(request, tmp_path_factory)
@pytest.fixture @fixture
def testdir(pytester: "Pytester") -> "Testdir": def testdir(pytester: "Pytester") -> "Testdir":
""" """
Identical to :fixture:`pytester`, and provides an instance whose methods return Identical to :fixture:`pytester`, and provides an instance whose methods return
@ -460,7 +466,7 @@ def testdir(pytester: "Pytester") -> "Testdir":
return Testdir(pytester) return Testdir(pytester)
@pytest.fixture @fixture
def _sys_snapshot() -> Generator[None, None, None]: def _sys_snapshot() -> Generator[None, None, None]:
snappaths = SysPathsSnapshot() snappaths = SysPathsSnapshot()
snapmods = SysModulesSnapshot() snapmods = SysModulesSnapshot()
@ -469,7 +475,7 @@ def _sys_snapshot() -> Generator[None, None, None]:
snappaths.restore() snappaths.restore()
@pytest.fixture @fixture
def _config_for_test() -> Generator[Config, None, None]: def _config_for_test() -> Generator[Config, None, None]:
from _pytest.config import get_config from _pytest.config import get_config
@ -495,7 +501,7 @@ class RunResult:
duration: float, duration: float,
) -> None: ) -> None:
try: try:
self.ret: Union[int, ExitCode] = pytest.ExitCode(ret) self.ret: Union[int, ExitCode] = ExitCode(ret)
"""The return value.""" """The return value."""
except ValueError: except ValueError:
self.ret = ret self.ret = ret
@ -1062,7 +1068,7 @@ class Pytester:
rec.append(self.make_hook_recorder(config.pluginmanager)) rec.append(self.make_hook_recorder(config.pluginmanager))
plugins.append(Collect()) plugins.append(Collect())
ret = pytest.main([str(x) for x in args], plugins=plugins) ret = main([str(x) for x in args], plugins=plugins)
if len(rec) == 1: if len(rec) == 1:
reprec = rec.pop() reprec = rec.pop()
else: else:
@ -1448,11 +1454,11 @@ class Pytester:
The pexpect child is returned. The pexpect child is returned.
""" """
pexpect = pytest.importorskip("pexpect", "3.0") pexpect = importorskip("pexpect", "3.0")
if hasattr(sys, "pypy_version_info") and "64" in platform.machine(): if hasattr(sys, "pypy_version_info") and "64" in platform.machine():
pytest.skip("pypy-64 bit not supported") skip("pypy-64 bit not supported")
if not hasattr(pexpect, "spawn"): if not hasattr(pexpect, "spawn"):
pytest.skip("pexpect.spawn not available") skip("pexpect.spawn not available")
logfile = self.path.joinpath("spawn.out").open("wb") logfile = self.path.joinpath("spawn.out").open("wb")
child = pexpect.spawn(cmd, logfile=logfile, timeout=expect_timeout) child = pexpect.spawn(cmd, logfile=logfile, timeout=expect_timeout)
@ -1899,7 +1905,7 @@ class LineMatcher:
__tracebackhide__ = True __tracebackhide__ = True
log_text = self._log_text log_text = self._log_text
self._log_output = [] self._log_output = []
pytest.fail(log_text) fail(log_text)
def str(self) -> str: def str(self) -> str:
"""Return the entire original text.""" """Return the entire original text."""

View File

@ -29,7 +29,7 @@ import attr
import pluggy import pluggy
import py import py
import pytest import _pytest._version
from _pytest import nodes from _pytest import nodes
from _pytest import timing from _pytest import timing
from _pytest._code import ExceptionInfo from _pytest._code import ExceptionInfo
@ -39,6 +39,7 @@ from _pytest.compat import final
from _pytest.config import _PluggyPlugin from _pytest.config import _PluggyPlugin
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.config import hookimpl
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.nodes import Item from _pytest.nodes import Item
from _pytest.nodes import Node from _pytest.nodes import Node
@ -259,7 +260,7 @@ def getreportopt(config: Config) -> str:
return reportopts return reportopts
@pytest.hookimpl(trylast=True) # after _pytest.runner @hookimpl(trylast=True) # after _pytest.runner
def pytest_report_teststatus(report: BaseReport) -> Tuple[str, str, str]: def pytest_report_teststatus(report: BaseReport) -> Tuple[str, str, str]:
letter = "F" letter = "F"
if report.passed: if report.passed:
@ -628,7 +629,7 @@ class TerminalReporter:
self._add_stats("error", [report]) self._add_stats("error", [report])
elif report.skipped: elif report.skipped:
self._add_stats("skipped", [report]) self._add_stats("skipped", [report])
items = [x for x in report.result if isinstance(x, pytest.Item)] items = [x for x in report.result if isinstance(x, Item)]
self._numcollected += len(items) self._numcollected += len(items)
if self.isatty: if self.isatty:
self.report_collect() self.report_collect()
@ -673,7 +674,7 @@ class TerminalReporter:
else: else:
self.write_line(line) self.write_line(line)
@pytest.hookimpl(trylast=True) @hookimpl(trylast=True)
def pytest_sessionstart(self, session: "Session") -> None: def pytest_sessionstart(self, session: "Session") -> None:
self._session = session self._session = session
self._sessionstarttime = timing.time() self._sessionstarttime = timing.time()
@ -688,7 +689,7 @@ class TerminalReporter:
verinfo = ".".join(map(str, pypy_version_info[:3])) verinfo = ".".join(map(str, pypy_version_info[:3]))
msg += "[pypy-{}-{}]".format(verinfo, pypy_version_info[3]) msg += "[pypy-{}-{}]".format(verinfo, pypy_version_info[3])
msg += ", pytest-{}, py-{}, pluggy-{}".format( msg += ", pytest-{}, py-{}, pluggy-{}".format(
pytest.__version__, py.__version__, pluggy.__version__ _pytest._version.version, py.__version__, pluggy.__version__
) )
if ( if (
self.verbosity > 0 self.verbosity > 0
@ -783,7 +784,7 @@ class TerminalReporter:
for line in doc.splitlines(): for line in doc.splitlines():
self._tw.line("{}{}".format(indent + " ", line)) self._tw.line("{}{}".format(indent + " ", line))
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_sessionfinish( def pytest_sessionfinish(
self, session: "Session", exitstatus: Union[int, ExitCode] self, session: "Session", exitstatus: Union[int, ExitCode]
): ):
@ -810,7 +811,7 @@ class TerminalReporter:
self.write_sep("!", str(session.shouldstop), red=True) self.write_sep("!", str(session.shouldstop), red=True)
self.summary_stats() self.summary_stats()
@pytest.hookimpl(hookwrapper=True) @hookimpl(hookwrapper=True)
def pytest_terminal_summary(self) -> Generator[None, None, None]: def pytest_terminal_summary(self) -> Generator[None, None, None]:
self.summary_errors() self.summary_errors()
self.summary_failures() self.summary_failures()

View File

@ -8,13 +8,13 @@ from typing import Optional
import attr import attr
import py import py
import pytest
from .pathlib import ensure_reset_dir from .pathlib import ensure_reset_dir
from .pathlib import LOCK_TIMEOUT from .pathlib import LOCK_TIMEOUT
from .pathlib import make_numbered_dir from .pathlib import make_numbered_dir
from .pathlib import make_numbered_dir_with_cleanup from .pathlib import make_numbered_dir_with_cleanup
from _pytest.compat import final from _pytest.compat import final
from _pytest.config import Config from _pytest.config import Config
from _pytest.fixtures import fixture
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
@ -146,14 +146,14 @@ def pytest_configure(config: Config) -> None:
mp.setattr(config, "_tmpdirhandler", t, raising=False) mp.setattr(config, "_tmpdirhandler", t, raising=False)
@pytest.fixture(scope="session") @fixture(scope="session")
def tmpdir_factory(request: FixtureRequest) -> TempdirFactory: def tmpdir_factory(request: FixtureRequest) -> TempdirFactory:
"""Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.""" """Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session."""
# Set dynamically by pytest_configure() above. # Set dynamically by pytest_configure() above.
return request.config._tmpdirhandler # type: ignore return request.config._tmpdirhandler # type: ignore
@pytest.fixture(scope="session") @fixture(scope="session")
def tmp_path_factory(request: FixtureRequest) -> TempPathFactory: def tmp_path_factory(request: FixtureRequest) -> TempPathFactory:
"""Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.""" """Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session."""
# Set dynamically by pytest_configure() above. # Set dynamically by pytest_configure() above.
@ -168,7 +168,7 @@ def _mk_tmp(request: FixtureRequest, factory: TempPathFactory) -> Path:
return factory.mktemp(name, numbered=True) return factory.mktemp(name, numbered=True)
@pytest.fixture @fixture
def tmpdir(tmp_path: Path) -> py.path.local: def tmpdir(tmp_path: Path) -> py.path.local:
"""Return a temporary directory path object which is unique to each test """Return a temporary directory path object which is unique to each test
function invocation, created as a sub directory of the base temporary function invocation, created as a sub directory of the base temporary
@ -181,7 +181,7 @@ def tmpdir(tmp_path: Path) -> py.path.local:
return py.path.local(tmp_path) return py.path.local(tmp_path)
@pytest.fixture @fixture
def tmp_path(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> Path: def tmp_path(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> Path:
"""Return a temporary directory path object which is unique to each test """Return a temporary directory path object which is unique to each test
function invocation, created as a sub directory of the base temporary function invocation, created as a sub directory of the base temporary