def make_call_info(exc_info, *, start, stop, duration, when): try: return CallInfo( None, exc_info, start=start, stop=stop, duration=duration, when=when ) except TypeError: # support for pytest<6: didn't have a duration parameter then return CallInfo(None, exc_info, start=start, stop=stop, when=when)
def __init__(self, plugin, item, func, when): # pylint:disable=super-init-not-called #: context of invocation: one of "setup", "call", #: "teardown", "memocollect" self._item = item self._want_rerun = [] self.excinfo = None from functools import partial CallInfo.__init__(self, partial(self.call, func, plugin), when)
def run_fictitious_testprotocol(item): """ REMINDER: Tests have already run on subprocess. Here we just need to convince the current pytest process that the tests have already run and to collect their reports. """ call = CallInfo.from_call(lambda: True, when="setup", reraise=(Exit, )) item.ihook.pytest_runtest_makereport(item=item, call=call) call = CallInfo.from_call(lambda: True, when="call", reraise=(Exit, )) item.ihook.pytest_runtest_makereport(item=item, call=call) call = CallInfo.from_call(lambda: True, when="teardown", reraise=(Exit, )) item.ihook.pytest_runtest_makereport(item=item, call=call)
def _addSubTest(self, test_case, test, exc_info): if exc_info is not None: msg = test._message if isinstance(test._message, str) else None call_info = CallInfo(None, ExceptionInfo(exc_info), 0, 0, when="call") sub_report = SubTestReport.from_item_and_call(item=self, call=call_info) sub_report.context = SubTestContext(msg, dict(test.params)) self.ihook.pytest_runtest_logreport(report=sub_report)
def pytest_runtest_makereport(item, call): if isinstance(item, TestCaseFunction): if item._excinfo: call.excinfo = item._excinfo.pop(0) try: del call.result except AttributeError: pass unittest = sys.modules.get("unittest") if unittest and call.excinfo and call.excinfo.errisinstance( unittest.SkipTest): # let's substitute the excinfo with a pytest.skip one call2 = CallInfo.from_call( lambda: pytest.skip(str(call.excinfo.value)), call.when) call.excinfo = call2.excinfo
def call_runtest_hook(self, item, when, **kwds): """ Monkey patched from the runner plugin. Responsible for running the test. Had to be patched to pass additional info to the CallInfo so the tests can be rerun if necessary. :param item: py.test wrapper for the test function to be run :type item: :class:`Function` """ hookname = "pytest_runtest_" + when ihook = getattr(item.ihook, hookname) call_info = CallInfo( lambda: ihook(item=item, **kwds), when=when, ) self._call_infos[item][when] = call_info return call_info
def test(self, msg=None, **kwargs): start = monotonic() exc_info = None with self._capturing_output() as captured: try: yield except (Exception, OutcomeException): exc_info = ExceptionInfo.from_current() stop = monotonic() call_info = CallInfo(None, exc_info, start, stop, when="call") sub_report = SubTestReport.from_item_and_call(item=self.item, call=call_info) sub_report.context = SubTestContext(msg, kwargs.copy()) captured.update_report(sub_report) with self.suspend_capture_ctx(): self.ihook.pytest_runtest_logreport(report=sub_report)
def pytest_pyfunc_call(pyfuncitem): if not pyfuncitem.config.option.reload_loop: return None else: testfunction = pyfuncitem.obj iscoroutinefunction = getattr(inspect, "iscoroutinefunction", None) if iscoroutinefunction is not None and iscoroutinefunction( testfunction): msg = "Coroutine functions are not natively supported and have been skipped.\n" msg += "You need to install a suitable plugin for your async framework, for example:\n" msg += " - pytest-asyncio\n" msg += " - pytest-trio\n" msg += " - pytest-tornasync" warnings.warn(pytest.PytestWarning(msg.format(pyfuncitem.nodeid))) pytest.skip( msg= "coroutine function and no async plugin installed (see warnings)" ) funcargs = pyfuncitem.funcargs testargs = { arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames } passing = False while not passing: info = CallInfo.from_call(lambda: testfunction(**testargs), when="call", reraise=None) # if info.excinfo: if info.excinfo: # build the pytest report report = pyfuncitem.ihook.pytest_runtest_makereport( item=pyfuncitem, call=info) _enter_pdb(pyfuncitem, info.excinfo, report) else: passing = True # after you've successfully gotten the test to pass run it one more time # (this hack exists because of the hookwrapper logic) return info
def fake_process(trace_fname): config = ctype(otype(trace_fname, 4), PytestPluginManager(), lambda x, y: 0) plugin = ApiritifPytestPlugin(config) next(plugin.pytest_runtest_setup(None)) yield node = Node._create("test", nodeid="tst", config=config, session="some") node._report_sections = [] node.location = [] node.user_properties = [] call = CallInfo.from_call(lambda: 1, 'call') report = TestReport.from_item_and_call(node, call) result = _Result(report, None) gen = plugin.pytest_runtest_makereport(node, call) next(gen) try: gen.send(result) except StopIteration: pass plugin.pytest_sessionfinish(None)
def run_function_from_file(item, params=None): file, _, func = item.location marker = item.get_closest_marker("subprocess") file_index = 1 args = marker.kwargs.get("args", []) args.insert(0, None) args.insert(0, sys.executable) if marker.kwargs.get("ddtrace_run", False): file_index += 1 args.insert(0, "ddtrace-run") env = os.environ.copy() env.update(marker.kwargs.get("env", {})) if params is not None: env.update(params) expected_status = marker.kwargs.get("status", 0) expected_out = marker.kwargs.get("out", "") if expected_out is not None: expected_out = expected_out.encode("utf-8") expected_err = marker.kwargs.get("err", "") if expected_err is not None: expected_err = expected_err.encode("utf-8") with NamedTemporaryFile(mode="wb", suffix=".pyc") as fp: dump_code_to_file( compile(FunctionDefFinder(func).find(file), file, "exec"), fp.file) start = time.time() args[file_index] = fp.name out, err, status, _ = call_program(*args, env=env) end = time.time() excinfo = None if status != expected_status: excinfo = AssertionError( "Expected status %s, got %s.\n=== Captured STDERR ===\n%s=== End of captured STDERR ===" % (expected_status, status, err.decode("utf-8"))) elif expected_out is not None and out != expected_out: excinfo = AssertionError("STDOUT: Expected [%s] got [%s]" % (expected_out, out)) elif expected_err is not None and err != expected_err: excinfo = AssertionError("STDERR: Expected [%s] got [%s]" % (expected_err, err)) if PY2 and excinfo is not None: try: raise excinfo except Exception: excinfo = ExceptionInfo(sys.exc_info()) call_info_args = dict(result=None, excinfo=excinfo, start=start, stop=end, when="call") if not PY2: call_info_args["duration"] = end - start return TestReport.from_item_and_call(item, CallInfo(**call_info_args))
def call_runtest_hook(self, item, when, **kwds): hookname = "pytest_runtest_" + when ihook = getattr(item.ihook, hookname) return CallInfo(lambda: ihook(item=item, **kwds), when=when)