@@ -112,8 +112,8 @@ def pytest_collection(session: "Session") -> None:
|
||||
assertstate.hook.set_session(session)
|
||||
|
||||
|
||||
@hookimpl(tryfirst=True, hookwrapper=True)
|
||||
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||
@hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
|
||||
"""Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks.
|
||||
|
||||
The rewrite module will use util._reprcompare if it exists to use custom
|
||||
@@ -162,10 +162,11 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||
|
||||
util._assertion_pass = call_assertion_pass_hook
|
||||
|
||||
yield
|
||||
|
||||
util._reprcompare, util._assertion_pass = saved_assert_hooks
|
||||
util._config = None
|
||||
try:
|
||||
return (yield)
|
||||
finally:
|
||||
util._reprcompare, util._assertion_pass = saved_assert_hooks
|
||||
util._config = None
|
||||
|
||||
|
||||
def pytest_sessionfinish(session: "Session") -> None:
|
||||
|
||||
@@ -217,12 +217,12 @@ class LFPluginCollWrapper:
|
||||
self.lfplugin = lfplugin
|
||||
self._collected_at_least_one_failure = False
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_make_collect_report(self, collector: nodes.Collector):
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_make_collect_report(
|
||||
self, collector: nodes.Collector
|
||||
) -> Generator[None, CollectReport, CollectReport]:
|
||||
res = yield
|
||||
if isinstance(collector, (Session, Package)):
|
||||
out = yield
|
||||
res: CollectReport = out.get_result()
|
||||
|
||||
# Sort any lf-paths to the beginning.
|
||||
lf_paths = self.lfplugin._last_failed_paths
|
||||
|
||||
@@ -240,19 +240,16 @@ class LFPluginCollWrapper:
|
||||
key=sort_key,
|
||||
reverse=True,
|
||||
)
|
||||
return
|
||||
|
||||
elif isinstance(collector, File):
|
||||
if collector.path in self.lfplugin._last_failed_paths:
|
||||
out = yield
|
||||
res = out.get_result()
|
||||
result = res.result
|
||||
lastfailed = self.lfplugin.lastfailed
|
||||
|
||||
# Only filter with known failures.
|
||||
if not self._collected_at_least_one_failure:
|
||||
if not any(x.nodeid in lastfailed for x in result):
|
||||
return
|
||||
return res
|
||||
self.lfplugin.config.pluginmanager.register(
|
||||
LFPluginCollSkipfiles(self.lfplugin), "lfplugin-collskip"
|
||||
)
|
||||
@@ -268,8 +265,8 @@ class LFPluginCollWrapper:
|
||||
# Keep all sub-collectors.
|
||||
or isinstance(x, nodes.Collector)
|
||||
]
|
||||
return
|
||||
yield
|
||||
|
||||
return res
|
||||
|
||||
|
||||
class LFPluginCollSkipfiles:
|
||||
@@ -342,14 +339,14 @@ class LFPlugin:
|
||||
else:
|
||||
self.lastfailed[report.nodeid] = True
|
||||
|
||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_collection_modifyitems(
|
||||
self, config: Config, items: List[nodes.Item]
|
||||
) -> Generator[None, None, None]:
|
||||
yield
|
||||
res = yield
|
||||
|
||||
if not self.active:
|
||||
return
|
||||
return res
|
||||
|
||||
if self.lastfailed:
|
||||
previously_failed = []
|
||||
@@ -394,6 +391,8 @@ class LFPlugin:
|
||||
else:
|
||||
self._report_status += "not deselecting items."
|
||||
|
||||
return res
|
||||
|
||||
def pytest_sessionfinish(self, session: Session) -> None:
|
||||
config = self.config
|
||||
if config.getoption("cacheshow") or hasattr(config, "workerinput"):
|
||||
@@ -414,11 +413,11 @@ class NFPlugin:
|
||||
assert config.cache is not None
|
||||
self.cached_nodeids = set(config.cache.get("cache/nodeids", []))
|
||||
|
||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_collection_modifyitems(
|
||||
self, items: List[nodes.Item]
|
||||
) -> Generator[None, None, None]:
|
||||
yield
|
||||
res = yield
|
||||
|
||||
if self.active:
|
||||
new_items: Dict[str, nodes.Item] = {}
|
||||
@@ -436,6 +435,8 @@ class NFPlugin:
|
||||
else:
|
||||
self.cached_nodeids.update(item.nodeid for item in items)
|
||||
|
||||
return res
|
||||
|
||||
def _get_increasing_order(self, items: Iterable[nodes.Item]) -> List[nodes.Item]:
|
||||
return sorted(items, key=lambda item: item.path.stat().st_mtime, reverse=True) # type: ignore[no-any-return]
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ from _pytest.fixtures import SubRequest
|
||||
from _pytest.nodes import Collector
|
||||
from _pytest.nodes import File
|
||||
from _pytest.nodes import Item
|
||||
from _pytest.reports import CollectReport
|
||||
|
||||
_CaptureMethod = Literal["fd", "sys", "no", "tee-sys"]
|
||||
|
||||
@@ -130,8 +131,8 @@ def _windowsconsoleio_workaround(stream: TextIO) -> None:
|
||||
sys.stderr = _reopen_stdio(sys.stderr, "wb")
|
||||
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_load_initial_conftests(early_config: Config):
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_load_initial_conftests(early_config: Config) -> Generator[None, None, None]:
|
||||
ns = early_config.known_args_namespace
|
||||
if ns.capture == "fd":
|
||||
_windowsconsoleio_workaround(sys.stdout)
|
||||
@@ -145,12 +146,16 @@ def pytest_load_initial_conftests(early_config: Config):
|
||||
|
||||
# Finally trigger conftest loading but while capturing (issue #93).
|
||||
capman.start_global_capturing()
|
||||
outcome = yield
|
||||
capman.suspend_global_capture()
|
||||
if outcome.excinfo is not None:
|
||||
try:
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
capman.suspend_global_capture()
|
||||
except BaseException:
|
||||
out, err = capman.read_global_capture()
|
||||
sys.stdout.write(out)
|
||||
sys.stderr.write(err)
|
||||
raise
|
||||
|
||||
|
||||
# IO Helpers.
|
||||
@@ -841,41 +846,45 @@ class CaptureManager:
|
||||
self.deactivate_fixture()
|
||||
self.suspend_global_capture(in_=False)
|
||||
|
||||
out, err = self.read_global_capture()
|
||||
item.add_report_section(when, "stdout", out)
|
||||
item.add_report_section(when, "stderr", err)
|
||||
out, err = self.read_global_capture()
|
||||
item.add_report_section(when, "stdout", out)
|
||||
item.add_report_section(when, "stderr", err)
|
||||
|
||||
# Hooks
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_make_collect_report(self, collector: Collector):
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_make_collect_report(
|
||||
self, collector: Collector
|
||||
) -> Generator[None, CollectReport, CollectReport]:
|
||||
if isinstance(collector, File):
|
||||
self.resume_global_capture()
|
||||
outcome = yield
|
||||
self.suspend_global_capture()
|
||||
try:
|
||||
rep = yield
|
||||
finally:
|
||||
self.suspend_global_capture()
|
||||
out, err = self.read_global_capture()
|
||||
rep = outcome.get_result()
|
||||
if out:
|
||||
rep.sections.append(("Captured stdout", out))
|
||||
if err:
|
||||
rep.sections.append(("Captured stderr", err))
|
||||
else:
|
||||
yield
|
||||
rep = yield
|
||||
return rep
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtest_setup(self, item: Item) -> Generator[None, None, None]:
|
||||
with self.item_capture("setup", item):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtest_call(self, item: Item) -> Generator[None, None, None]:
|
||||
with self.item_capture("call", item):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtest_teardown(self, item: Item) -> Generator[None, None, None]:
|
||||
with self.item_capture("teardown", item):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
@hookimpl(tryfirst=True)
|
||||
def pytest_keyboard_interrupt(self) -> None:
|
||||
|
||||
@@ -1341,12 +1341,14 @@ class Config:
|
||||
else:
|
||||
raise
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_collection(self) -> Generator[None, None, None]:
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_collection(self) -> Generator[None, object, object]:
|
||||
# Validate invalid ini keys after collection is done so we take in account
|
||||
# options added by late-loading conftest files.
|
||||
yield
|
||||
self._validate_config_options()
|
||||
try:
|
||||
return (yield)
|
||||
finally:
|
||||
self._validate_config_options()
|
||||
|
||||
def _checkversion(self) -> None:
|
||||
import pytest
|
||||
@@ -1448,7 +1450,7 @@ class Config:
|
||||
"""Issue and handle a warning during the "configure" stage.
|
||||
|
||||
During ``pytest_configure`` we can't capture warnings using the ``catch_warnings_for_item``
|
||||
function because it is not possible to have hookwrappers around ``pytest_configure``.
|
||||
function because it is not possible to have hook wrappers around ``pytest_configure``.
|
||||
|
||||
This function is mainly intended for plugins that need to issue warnings during
|
||||
``pytest_configure`` (or similar stages).
|
||||
|
||||
@@ -304,10 +304,10 @@ class PdbInvoke:
|
||||
|
||||
|
||||
class PdbTrace:
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_pyfunc_call(self, pyfuncitem) -> Generator[None, None, None]:
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_pyfunc_call(self, pyfuncitem) -> Generator[None, object, object]:
|
||||
wrap_pytest_function_for_tracing(pyfuncitem)
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
|
||||
def wrap_pytest_function_for_tracing(pyfuncitem):
|
||||
|
||||
@@ -62,8 +62,8 @@ def get_timeout_config_value(config: Config) -> float:
|
||||
return float(config.getini("faulthandler_timeout") or 0.0)
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, trylast=True)
|
||||
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||
@pytest.hookimpl(wrapper=True, trylast=True)
|
||||
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
|
||||
timeout = get_timeout_config_value(item.config)
|
||||
if timeout > 0:
|
||||
import faulthandler
|
||||
@@ -71,11 +71,11 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||
stderr = item.config.stash[fault_handler_stderr_fd_key]
|
||||
faulthandler.dump_traceback_later(timeout, file=stderr)
|
||||
try:
|
||||
yield
|
||||
return (yield)
|
||||
finally:
|
||||
faulthandler.cancel_dump_traceback_later()
|
||||
else:
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
|
||||
@pytest.hookimpl(tryfirst=True)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import os
|
||||
import sys
|
||||
from argparse import Action
|
||||
from typing import Generator
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
@@ -97,10 +98,9 @@ def pytest_addoption(parser: Parser) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
def pytest_cmdline_parse():
|
||||
outcome = yield
|
||||
config: Config = outcome.get_result()
|
||||
@pytest.hookimpl(wrapper=True)
|
||||
def pytest_cmdline_parse() -> Generator[None, Config, Config]:
|
||||
config = yield
|
||||
|
||||
if config.option.debug:
|
||||
# --debug | --debug <file.log> was provided.
|
||||
@@ -128,6 +128,8 @@ def pytest_cmdline_parse():
|
||||
|
||||
config.add_cleanup(unset_tracing)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def showversion(config: Config) -> None:
|
||||
if config.option.version > 1:
|
||||
|
||||
@@ -60,7 +60,7 @@ def pytest_addhooks(pluginmanager: "PytestPluginManager") -> None:
|
||||
:param pytest.PytestPluginManager pluginmanager: The pytest plugin manager.
|
||||
|
||||
.. note::
|
||||
This hook is incompatible with ``hookwrapper=True``.
|
||||
This hook is incompatible with hook wrappers.
|
||||
"""
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ def pytest_plugin_registered(
|
||||
:param pytest.PytestPluginManager manager: pytest plugin manager.
|
||||
|
||||
.. note::
|
||||
This hook is incompatible with ``hookwrapper=True``.
|
||||
This hook is incompatible with hook wrappers.
|
||||
"""
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ def pytest_addoption(parser: "Parser", pluginmanager: "PytestPluginManager") ->
|
||||
attribute or can be retrieved as the ``pytestconfig`` fixture.
|
||||
|
||||
.. note::
|
||||
This hook is incompatible with ``hookwrapper=True``.
|
||||
This hook is incompatible with hook wrappers.
|
||||
"""
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ def pytest_configure(config: "Config") -> None:
|
||||
imported.
|
||||
|
||||
.. note::
|
||||
This hook is incompatible with ``hookwrapper=True``.
|
||||
This hook is incompatible with hook wrappers.
|
||||
|
||||
:param pytest.Config config: The pytest config object.
|
||||
"""
|
||||
|
||||
@@ -738,27 +738,26 @@ class LoggingPlugin:
|
||||
|
||||
return True
|
||||
|
||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_sessionstart(self) -> Generator[None, None, None]:
|
||||
self.log_cli_handler.set_when("sessionstart")
|
||||
|
||||
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_collection(self) -> Generator[None, None, None]:
|
||||
self.log_cli_handler.set_when("collection")
|
||||
|
||||
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_runtestloop(self, session: Session) -> Generator[None, None, None]:
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtestloop(self, session: Session) -> Generator[None, object, object]:
|
||||
if session.config.option.collectonly:
|
||||
yield
|
||||
return
|
||||
return (yield)
|
||||
|
||||
if self._log_cli_enabled() and self._config.getoption("verbose") < 1:
|
||||
# The verbose flag is needed to avoid messy test progress output.
|
||||
@@ -766,7 +765,7 @@ class LoggingPlugin:
|
||||
|
||||
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||
yield # Run all the tests.
|
||||
return (yield) # Run all the tests.
|
||||
|
||||
@hookimpl
|
||||
def pytest_runtest_logstart(self) -> None:
|
||||
@@ -791,12 +790,13 @@ class LoggingPlugin:
|
||||
item.stash[caplog_records_key][when] = caplog_handler.records
|
||||
item.stash[caplog_handler_key] = caplog_handler
|
||||
|
||||
yield
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
log = report_handler.stream.getvalue().strip()
|
||||
item.add_report_section(when, "log", log)
|
||||
|
||||
log = report_handler.stream.getvalue().strip()
|
||||
item.add_report_section(when, "log", log)
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]:
|
||||
self.log_cli_handler.set_when("setup")
|
||||
|
||||
@@ -804,31 +804,33 @@ class LoggingPlugin:
|
||||
item.stash[caplog_records_key] = empty
|
||||
yield from self._runtest_for(item, "setup")
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtest_call(self, item: nodes.Item) -> Generator[None, None, None]:
|
||||
self.log_cli_handler.set_when("call")
|
||||
|
||||
yield from self._runtest_for(item, "call")
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtest_teardown(self, item: nodes.Item) -> Generator[None, None, None]:
|
||||
self.log_cli_handler.set_when("teardown")
|
||||
|
||||
yield from self._runtest_for(item, "teardown")
|
||||
del item.stash[caplog_records_key]
|
||||
del item.stash[caplog_handler_key]
|
||||
try:
|
||||
yield from self._runtest_for(item, "teardown")
|
||||
finally:
|
||||
del item.stash[caplog_records_key]
|
||||
del item.stash[caplog_handler_key]
|
||||
|
||||
@hookimpl
|
||||
def pytest_runtest_logfinish(self) -> None:
|
||||
self.log_cli_handler.set_when("finish")
|
||||
|
||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_sessionfinish(self) -> Generator[None, None, None]:
|
||||
self.log_cli_handler.set_when("sessionfinish")
|
||||
|
||||
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
@hookimpl
|
||||
def pytest_unconfigure(self) -> None:
|
||||
|
||||
@@ -160,29 +160,31 @@ class LsofFdLeakChecker:
|
||||
else:
|
||||
return True
|
||||
|
||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
||||
def pytest_runtest_protocol(self, item: Item) -> Generator[None, None, None]:
|
||||
@hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_runtest_protocol(self, item: Item) -> Generator[None, object, object]:
|
||||
lines1 = self.get_open_files()
|
||||
yield
|
||||
if hasattr(sys, "pypy_version_info"):
|
||||
gc.collect()
|
||||
lines2 = self.get_open_files()
|
||||
try:
|
||||
return (yield)
|
||||
finally:
|
||||
if hasattr(sys, "pypy_version_info"):
|
||||
gc.collect()
|
||||
lines2 = self.get_open_files()
|
||||
|
||||
new_fds = {t[0] for t in lines2} - {t[0] for t in lines1}
|
||||
leaked_files = [t for t in lines2 if t[0] in new_fds]
|
||||
if leaked_files:
|
||||
error = [
|
||||
"***** %s FD leakage detected" % len(leaked_files),
|
||||
*(str(f) for f in leaked_files),
|
||||
"*** Before:",
|
||||
*(str(f) for f in lines1),
|
||||
"*** After:",
|
||||
*(str(f) for f in lines2),
|
||||
"***** %s FD leakage detected" % len(leaked_files),
|
||||
"*** function %s:%s: %s " % item.location,
|
||||
"See issue #2366",
|
||||
]
|
||||
item.warn(PytestWarning("\n".join(error)))
|
||||
new_fds = {t[0] for t in lines2} - {t[0] for t in lines1}
|
||||
leaked_files = [t for t in lines2 if t[0] in new_fds]
|
||||
if leaked_files:
|
||||
error = [
|
||||
"***** %s FD leakage detected" % len(leaked_files),
|
||||
*(str(f) for f in leaked_files),
|
||||
"*** Before:",
|
||||
*(str(f) for f in lines1),
|
||||
"*** After:",
|
||||
*(str(f) for f in lines2),
|
||||
"***** %s FD leakage detected" % len(leaked_files),
|
||||
"*** function %s:%s: %s " % item.location,
|
||||
"See issue #2366",
|
||||
]
|
||||
item.warn(PytestWarning("\n".join(error)))
|
||||
|
||||
|
||||
# used at least by pytest-xdist plugin
|
||||
|
||||
@@ -249,6 +249,9 @@ class TestReport(BaseReport):
|
||||
"""
|
||||
|
||||
__test__ = False
|
||||
# Defined by skipping plugin.
|
||||
# xfail reason if xfailed, otherwise not defined. Use hasattr to distinguish.
|
||||
wasxfail: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -28,24 +28,26 @@ def pytest_addoption(parser: Parser) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
@pytest.hookimpl(wrapper=True)
|
||||
def pytest_fixture_setup(
|
||||
fixturedef: FixtureDef[object], request: SubRequest
|
||||
) -> Generator[None, None, None]:
|
||||
yield
|
||||
if request.config.option.setupshow:
|
||||
if hasattr(request, "param"):
|
||||
# Save the fixture parameter so ._show_fixture_action() can
|
||||
# display it now and during the teardown (in .finish()).
|
||||
if fixturedef.ids:
|
||||
if callable(fixturedef.ids):
|
||||
param = fixturedef.ids(request.param)
|
||||
) -> Generator[None, object, object]:
|
||||
try:
|
||||
return (yield)
|
||||
finally:
|
||||
if request.config.option.setupshow:
|
||||
if hasattr(request, "param"):
|
||||
# Save the fixture parameter so ._show_fixture_action() can
|
||||
# display it now and during the teardown (in .finish()).
|
||||
if fixturedef.ids:
|
||||
if callable(fixturedef.ids):
|
||||
param = fixturedef.ids(request.param)
|
||||
else:
|
||||
param = fixturedef.ids[request.param_index]
|
||||
else:
|
||||
param = fixturedef.ids[request.param_index]
|
||||
else:
|
||||
param = request.param
|
||||
fixturedef.cached_param = param # type: ignore[attr-defined]
|
||||
_show_fixture_action(fixturedef, "SETUP")
|
||||
param = request.param
|
||||
fixturedef.cached_param = param # type: ignore[attr-defined]
|
||||
_show_fixture_action(fixturedef, "SETUP")
|
||||
|
||||
|
||||
def pytest_fixture_post_finalizer(fixturedef: FixtureDef[object]) -> None:
|
||||
|
||||
@@ -19,6 +19,7 @@ from _pytest.outcomes import fail
|
||||
from _pytest.outcomes import skip
|
||||
from _pytest.outcomes import xfail
|
||||
from _pytest.reports import BaseReport
|
||||
from _pytest.reports import TestReport
|
||||
from _pytest.runner import CallInfo
|
||||
from _pytest.stash import StashKey
|
||||
|
||||
@@ -243,7 +244,7 @@ def pytest_runtest_setup(item: Item) -> None:
|
||||
xfail("[NOTRUN] " + xfailed.reason)
|
||||
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtest_call(item: Item) -> Generator[None, None, None]:
|
||||
xfailed = item.stash.get(xfailed_key, None)
|
||||
if xfailed is None:
|
||||
@@ -252,18 +253,20 @@ def pytest_runtest_call(item: Item) -> Generator[None, None, None]:
|
||||
if xfailed and not item.config.option.runxfail and not xfailed.run:
|
||||
xfail("[NOTRUN] " + xfailed.reason)
|
||||
|
||||
yield
|
||||
|
||||
# The test run may have added an xfail mark dynamically.
|
||||
xfailed = item.stash.get(xfailed_key, None)
|
||||
if xfailed is None:
|
||||
item.stash[xfailed_key] = xfailed = evaluate_xfail_marks(item)
|
||||
try:
|
||||
return (yield)
|
||||
finally:
|
||||
# The test run may have added an xfail mark dynamically.
|
||||
xfailed = item.stash.get(xfailed_key, None)
|
||||
if xfailed is None:
|
||||
item.stash[xfailed_key] = xfailed = evaluate_xfail_marks(item)
|
||||
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_runtest_makereport(item: Item, call: CallInfo[None]):
|
||||
outcome = yield
|
||||
rep = outcome.get_result()
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtest_makereport(
|
||||
item: Item, call: CallInfo[None]
|
||||
) -> Generator[None, TestReport, TestReport]:
|
||||
rep = yield
|
||||
xfailed = item.stash.get(xfailed_key, None)
|
||||
if item.config.option.runxfail:
|
||||
pass # don't interfere
|
||||
@@ -286,6 +289,7 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]):
|
||||
else:
|
||||
rep.outcome = "passed"
|
||||
rep.wasxfail = xfailed.reason
|
||||
return rep
|
||||
|
||||
|
||||
def pytest_report_teststatus(report: BaseReport) -> Optional[Tuple[str, str, str]]:
|
||||
|
||||
@@ -15,7 +15,6 @@ from functools import partial
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import cast
|
||||
from typing import ClassVar
|
||||
from typing import Dict
|
||||
from typing import final
|
||||
@@ -849,12 +848,11 @@ class TerminalReporter:
|
||||
for line in doc.splitlines():
|
||||
self._tw.line("{}{}".format(indent + " ", line))
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_sessionfinish(
|
||||
self, session: "Session", exitstatus: Union[int, ExitCode]
|
||||
):
|
||||
outcome = yield
|
||||
outcome.get_result()
|
||||
) -> Generator[None, None, None]:
|
||||
result = yield
|
||||
self._tw.line("")
|
||||
summary_exit_codes = (
|
||||
ExitCode.OK,
|
||||
@@ -875,17 +873,20 @@ class TerminalReporter:
|
||||
elif session.shouldstop:
|
||||
self.write_sep("!", str(session.shouldstop), red=True)
|
||||
self.summary_stats()
|
||||
return result
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_terminal_summary(self) -> Generator[None, None, None]:
|
||||
self.summary_errors()
|
||||
self.summary_failures()
|
||||
self.summary_warnings()
|
||||
self.summary_passes()
|
||||
yield
|
||||
self.short_test_summary()
|
||||
# Display any extra warnings from teardown here (if any).
|
||||
self.summary_warnings()
|
||||
try:
|
||||
return (yield)
|
||||
finally:
|
||||
self.short_test_summary()
|
||||
# Display any extra warnings from teardown here (if any).
|
||||
self.summary_warnings()
|
||||
|
||||
def pytest_keyboard_interrupt(self, excinfo: ExceptionInfo[BaseException]) -> None:
|
||||
self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True)
|
||||
@@ -1466,7 +1467,7 @@ def _get_raw_skip_reason(report: TestReport) -> str:
|
||||
The string is just the part given by the user.
|
||||
"""
|
||||
if hasattr(report, "wasxfail"):
|
||||
reason = cast(str, report.wasxfail)
|
||||
reason = report.wasxfail
|
||||
if reason.startswith("reason: "):
|
||||
reason = reason[len("reason: ") :]
|
||||
return reason
|
||||
|
||||
@@ -59,30 +59,34 @@ class catch_threading_exception:
|
||||
|
||||
def thread_exception_runtest_hook() -> Generator[None, None, None]:
|
||||
with catch_threading_exception() as cm:
|
||||
yield
|
||||
if cm.args:
|
||||
thread_name = "<unknown>" if cm.args.thread is None else cm.args.thread.name
|
||||
msg = f"Exception in thread {thread_name}\n\n"
|
||||
msg += "".join(
|
||||
traceback.format_exception(
|
||||
cm.args.exc_type,
|
||||
cm.args.exc_value,
|
||||
cm.args.exc_traceback,
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
if cm.args:
|
||||
thread_name = (
|
||||
"<unknown>" if cm.args.thread is None else cm.args.thread.name
|
||||
)
|
||||
)
|
||||
warnings.warn(pytest.PytestUnhandledThreadExceptionWarning(msg))
|
||||
msg = f"Exception in thread {thread_name}\n\n"
|
||||
msg += "".join(
|
||||
traceback.format_exception(
|
||||
cm.args.exc_type,
|
||||
cm.args.exc_value,
|
||||
cm.args.exc_traceback,
|
||||
)
|
||||
)
|
||||
warnings.warn(pytest.PytestUnhandledThreadExceptionWarning(msg))
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, trylast=True)
|
||||
@pytest.hookimpl(wrapper=True, trylast=True)
|
||||
def pytest_runtest_setup() -> Generator[None, None, None]:
|
||||
yield from thread_exception_runtest_hook()
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_runtest_call() -> Generator[None, None, None]:
|
||||
yield from thread_exception_runtest_hook()
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_runtest_teardown() -> Generator[None, None, None]:
|
||||
yield from thread_exception_runtest_hook()
|
||||
|
||||
@@ -28,7 +28,7 @@ from _pytest.fixtures import fixture
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
from _pytest.nodes import Item
|
||||
from _pytest.reports import CollectReport
|
||||
from _pytest.reports import TestReport
|
||||
from _pytest.stash import StashKey
|
||||
|
||||
tmppath_result_key = StashKey[Dict[str, bool]]()
|
||||
@@ -309,10 +309,12 @@ def pytest_sessionfinish(session, exitstatus: Union[int, ExitCode]):
|
||||
cleanup_dead_symlinks(basetemp)
|
||||
|
||||
|
||||
@hookimpl(tryfirst=True, hookwrapper=True)
|
||||
def pytest_runtest_makereport(item: Item, call):
|
||||
outcome = yield
|
||||
result: CollectReport = outcome.get_result()
|
||||
|
||||
@hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_runtest_makereport(
|
||||
item: Item, call
|
||||
) -> Generator[None, TestReport, TestReport]:
|
||||
rep = yield
|
||||
assert rep.when is not None
|
||||
empty: Dict[str, bool] = {}
|
||||
item.stash.setdefault(tmppath_result_key, empty)[result.when] = result.passed
|
||||
item.stash.setdefault(tmppath_result_key, empty)[rep.when] = rep.passed
|
||||
return rep
|
||||
|
||||
@@ -376,8 +376,8 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None:
|
||||
# Twisted trial support.
|
||||
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||
@hookimpl(wrapper=True)
|
||||
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
|
||||
if isinstance(item, TestCaseFunction) and "twisted.trial.unittest" in sys.modules:
|
||||
ut: Any = sys.modules["twisted.python.failure"]
|
||||
Failure__init__ = ut.Failure.__init__
|
||||
@@ -400,10 +400,13 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||
Failure__init__(self, exc_value, exc_type, exc_tb)
|
||||
|
||||
ut.Failure.__init__ = excstore
|
||||
yield
|
||||
ut.Failure.__init__ = Failure__init__
|
||||
try:
|
||||
res = yield
|
||||
finally:
|
||||
ut.Failure.__init__ = Failure__init__
|
||||
else:
|
||||
yield
|
||||
res = yield
|
||||
return res
|
||||
|
||||
|
||||
def check_testcase_implements_trial_reporter(done: List[int] = []) -> None:
|
||||
|
||||
@@ -61,33 +61,35 @@ class catch_unraisable_exception:
|
||||
|
||||
def unraisable_exception_runtest_hook() -> Generator[None, None, None]:
|
||||
with catch_unraisable_exception() as cm:
|
||||
yield
|
||||
if cm.unraisable:
|
||||
if cm.unraisable.err_msg is not None:
|
||||
err_msg = cm.unraisable.err_msg
|
||||
else:
|
||||
err_msg = "Exception ignored in"
|
||||
msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
|
||||
msg += "".join(
|
||||
traceback.format_exception(
|
||||
cm.unraisable.exc_type,
|
||||
cm.unraisable.exc_value,
|
||||
cm.unraisable.exc_traceback,
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
if cm.unraisable:
|
||||
if cm.unraisable.err_msg is not None:
|
||||
err_msg = cm.unraisable.err_msg
|
||||
else:
|
||||
err_msg = "Exception ignored in"
|
||||
msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
|
||||
msg += "".join(
|
||||
traceback.format_exception(
|
||||
cm.unraisable.exc_type,
|
||||
cm.unraisable.exc_value,
|
||||
cm.unraisable.exc_traceback,
|
||||
)
|
||||
)
|
||||
)
|
||||
warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
|
||||
warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_runtest_setup() -> Generator[None, None, None]:
|
||||
yield from unraisable_exception_runtest_hook()
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_runtest_call() -> Generator[None, None, None]:
|
||||
yield from unraisable_exception_runtest_hook()
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_runtest_teardown() -> Generator[None, None, None]:
|
||||
yield from unraisable_exception_runtest_hook()
|
||||
|
||||
@@ -60,17 +60,18 @@ def catch_warnings_for_item(
|
||||
for arg in mark.args:
|
||||
warnings.filterwarnings(*parse_warning_filter(arg, escape=False))
|
||||
|
||||
yield
|
||||
|
||||
for warning_message in log:
|
||||
ihook.pytest_warning_recorded.call_historic(
|
||||
kwargs=dict(
|
||||
warning_message=warning_message,
|
||||
nodeid=nodeid,
|
||||
when=when,
|
||||
location=None,
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
for warning_message in log:
|
||||
ihook.pytest_warning_recorded.call_historic(
|
||||
kwargs=dict(
|
||||
warning_message=warning_message,
|
||||
nodeid=nodeid,
|
||||
when=when,
|
||||
location=None,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def warning_record_to_str(warning_message: warnings.WarningMessage) -> str:
|
||||
@@ -103,24 +104,24 @@ def warning_record_to_str(warning_message: warnings.WarningMessage) -> str:
|
||||
return msg
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
|
||||
with catch_warnings_for_item(
|
||||
config=item.config, ihook=item.ihook, when="runtest", item=item
|
||||
):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||
def pytest_collection(session: Session) -> Generator[None, None, None]:
|
||||
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||
def pytest_collection(session: Session) -> Generator[None, object, object]:
|
||||
config = session.config
|
||||
with catch_warnings_for_item(
|
||||
config=config, ihook=config.hook, when="collect", item=None
|
||||
):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
@pytest.hookimpl(wrapper=True)
|
||||
def pytest_terminal_summary(
|
||||
terminalreporter: TerminalReporter,
|
||||
) -> Generator[None, None, None]:
|
||||
@@ -128,23 +129,23 @@ def pytest_terminal_summary(
|
||||
with catch_warnings_for_item(
|
||||
config=config, ihook=config.hook, when="config", item=None
|
||||
):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
@pytest.hookimpl(wrapper=True)
|
||||
def pytest_sessionfinish(session: Session) -> Generator[None, None, None]:
|
||||
config = session.config
|
||||
with catch_warnings_for_item(
|
||||
config=config, ihook=config.hook, when="config", item=None
|
||||
):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
@pytest.hookimpl(wrapper=True)
|
||||
def pytest_load_initial_conftests(
|
||||
early_config: "Config",
|
||||
) -> Generator[None, None, None]:
|
||||
with catch_warnings_for_item(
|
||||
config=early_config, ihook=early_config.hook, when="config", item=None
|
||||
):
|
||||
yield
|
||||
return (yield)
|
||||
|
||||
Reference in New Issue
Block a user