def test_exception_repr_extraction_error_on_recursion(): """ Ensure we can properly detect a recursion error even if some locals raise error on comparision (#2459). """ class numpy_like(object): def __eq__(self, other): if type(other) is numpy_like: raise ValueError('The truth value of an array ' 'with more than one element is ambiguous.') def a(x): return b(numpy_like()) def b(x): return a(numpy_like()) try: a(numpy_like()) except: from _pytest._code.code import ExceptionInfo from _pytest.pytester import LineMatcher exc_info = ExceptionInfo() matcher = LineMatcher(str(exc_info.getrepr()).splitlines()) matcher.fnmatch_lines([ '!!! Recursion error detected, but an error occurred locating the origin of recursion.', '*The following exception happened*', '*ValueError: The truth value of an array*', ])
def run_coro_as_main(loop, coro): class Captured(Exception): def __init__(self, error): self.error = error try: async def runner(): __tracebackhide__ = True try: await coro except: exc_info = sys.exc_info() exc_info[1].__traceback__ = exc_info[2] raise Captured(exc_info[1]) task = loop.create_task(runner()) loop.run_until_complete(task) except: exc_type, exc, tb = sys.exc_info() if issubclass(exc_type, Captured): exc = exc.error exc_type = type(exc) tb = exc.__traceback__ info = ExceptionInfo((exc_type, exc, tb), "") print(info.getrepr(style="short")) sys.exit(1) finally: cancel_all_tasks(loop, ignore_errors_from_tasks=[task]) loop.close()
def test_exception_repr_extraction_error_on_recursion(): """ Ensure we can properly detect a recursion error even if some locals raise error on comparision (#2459). """ class numpy_like(object): def __eq__(self, other): if type(other) is numpy_like: raise ValueError('The truth value of an array ' 'with more than one element is ambiguous.') def a(x): return b(numpy_like()) def b(x): return a(numpy_like()) try: a(numpy_like()) except: # noqa from _pytest._code.code import ExceptionInfo from _pytest.pytester import LineMatcher exc_info = ExceptionInfo() matcher = LineMatcher(str(exc_info.getrepr()).splitlines()) matcher.fnmatch_lines([ '!!! Recursion error detected, but an error occurred locating the origin of recursion.', '*The following exception happened*', '*ValueError: The truth value of an array*', ])
def handle_teardowns(item): __tracebackhide__ = True case = item._location teardown_groups = case._teardown_groups for group in teardown_groups: if group in case._helper._level_stack: start_time = time() try: group._teardown_group() except: # handle error during group setup excinfo = ExceptionInfo() stop_time = time() nodeid = item.nodeid.split("::")[0] + "::" nodeid += group._inline_description location = group._last_location keywords = {} outcome = "failed" longrepr = excinfo.getrepr() when = "teardown" sections = [] duration = stop_time - start_time context_lines = [ "Context:", "", ] context_lines += str(location).split("\n") context_lines[-1] = ">" + context_lines[-1][1:] entry = ReprEntry( context_lines, None, None, None, "long", ) if hasattr(longrepr, "chain"): reprtraceback = longrepr.chain[0][0] else: reprtraceback = longrepr.reprtraceback reprtraceback.reprentries.insert(0, entry) report = TestReport( nodeid, location, keywords, outcome, longrepr, when, sections, duration, ) item.ihook.pytest_runtest_logreport(report=report)
def _importtestmodule(self): # we assume we are only called once per module importmode = self.config.getoption("--import-mode") try: mod = self.fspath.pyimport(ensuresyspath=importmode) except SyntaxError: raise self.CollectError( _pytest._code.ExceptionInfo().getrepr(style="short") ) except self.fspath.ImportMismatchError: e = sys.exc_info()[1] raise self.CollectError( "import file mismatch:\n" "imported module %r has this __file__ attribute:\n" " %s\n" "which is not the same as the test file we want to collect:\n" " %s\n" "HINT: remove __pycache__ / .pyc files and/or use a " "unique basename for your test file modules" % e.args ) except ImportError: from _pytest._code.code import ExceptionInfo exc_info = ExceptionInfo() if self.config.getoption("verbose") < 2: exc_info.traceback = exc_info.traceback.filter(filter_traceback) exc_repr = ( exc_info.getrepr(style="short") if exc_info.traceback else exc_info.exconly() ) formatted_tb = safe_str(exc_repr) raise self.CollectError( "ImportError while importing test module '{fspath}'.\n" "Hint: make sure your test modules/packages have valid Python names.\n" "Traceback:\n" "{traceback}".format(fspath=self.fspath, traceback=formatted_tb) ) except _pytest.runner.Skipped as e: if e.allow_module_level: raise raise self.CollectError( "Using pytest.skip outside of a test is not allowed. " "To decorate a test function, use the @pytest.mark.skip " "or @pytest.mark.skipif decorators instead, and to skip a " "module use `pytestmark = pytest.mark.{skip,skipif}." ) self.config.pluginmanager.consider_module(mod) return mod
def pytest_runtest_makereport(item, call): outcome = yield report = outcome.get_result() failures = check_methods.get_failures() check_methods.clear_failures() if failures: if item._store[xfailed_key]: report.outcome = "skipped" report.wasxfail = item._store[xfailed_key].reason else: summary = "Failed Checks: {}".format(len(failures)) longrepr = ["\n".join(failures)] longrepr.append("-" * 60) longrepr.append(summary) if report.longrepr: longrepr.append("-" * 60) longrepr.append(report.longreprtext) report.longrepr = "\n".join(longrepr) else: report.longrepr = "\n".join(longrepr) report.outcome = "failed" try: raise AssertionError(report.longrepr) except AssertionError: excinfo = ExceptionInfo.from_current() call.excinfo = excinfo
def __init__(self, func, when, treat_keyboard_interrupt_as_exception=False): #: context of invocation: one of "setup", "call", #: "teardown", "memocollect" self.when = when self.start = time() try: self.result = func() except KeyboardInterrupt: if treat_keyboard_interrupt_as_exception: self.excinfo = ExceptionInfo() else: self.stop = time() raise except: # noqa self.excinfo = ExceptionInfo() self.stop = time()
def from_call( cls, func: "Callable[[], TResult]", when: "Literal['collect', 'setup', 'call', 'teardown']", reraise: Optional[Union[Type[BaseException], Tuple[Type[BaseException], ...]]] = None, ) -> "CallInfo[TResult]": excinfo = None start = timing.time() precise_start = timing.perf_counter() try: result: Optional[TResult] = func() except BaseException: excinfo = ExceptionInfo.from_current() if reraise is not None and isinstance(excinfo.value, reraise): raise result = None # use the perf counter precise_stop = timing.perf_counter() duration = precise_stop - precise_start stop = timing.time() return cls( start=start, stop=stop, duration=duration, when=when, result=result, excinfo=excinfo, )
def repr_failure(self, excinfo): import doctest failures = ( None ) # type: Optional[List[Union[doctest.DocTestFailure, doctest.UnexpectedException]]] if excinfo.errisinstance( (doctest.DocTestFailure, doctest.UnexpectedException)): failures = [excinfo.value] elif excinfo.errisinstance(MultipleDoctestFailures): failures = excinfo.value.failures if failures is not None: reprlocation_lines = [] for failure in failures: example = failure.example test = failure.test filename = test.filename if test.lineno is None: lineno = None else: lineno = test.lineno + example.lineno + 1 message = type(failure).__name__ reprlocation = ReprFileLocation(filename, lineno, message) checker = _get_checker() report_choice = _get_report_choice( self.config.getoption("doctestreport")) if lineno is not None: assert failure.test.docstring is not None lines = failure.test.docstring.splitlines(False) # add line numbers to the left of the error message assert test.lineno is not None lines = [ "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines) ] # trim docstring error lines to 10 lines = lines[max(example.lineno - 9, 0):example.lineno + 1] else: lines = [ "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example" ] indent = ">>>" for line in example.source.splitlines(): lines.append("??? {} {}".format(indent, line)) indent = "..." if isinstance(failure, doctest.DocTestFailure): lines += checker.output_difference( example, failure.got, report_choice).split("\n") else: inner_excinfo = ExceptionInfo(failure.exc_info) lines += [ "UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value) ] lines += traceback.format_exception(*failure.exc_info) reprlocation_lines.append((reprlocation, lines)) return ReprFailDoctest(reprlocation_lines) else: return super().repr_failure(excinfo)
def from_call(cls, func, when, reraise=None) -> "CallInfo": #: context of invocation: one of "setup", "call", #: "teardown", "memocollect" excinfo = None start = time() precise_start = perf_counter() try: result = func() except: # noqa excinfo = ExceptionInfo.from_current() if reraise is not None and excinfo.errisinstance(reraise): raise result = None # use the perf counter precise_stop = perf_counter() duration = precise_stop - precise_start stop = time() return cls( start=start, stop=stop, duration=duration, when=when, result=result, excinfo=excinfo, )
def test_no_recursion_index_on_recursion_error(): """ Ensure that we don't break in case we can't find the recursion index during a recursion error (#2486). """ try: class RecursionDepthError(object): def __getattr__(self, attr): return getattr(self, '_' + attr) RecursionDepthError().trigger except: # noqa from _pytest._code.code import ExceptionInfo exc_info = ExceptionInfo() assert 'maximum recursion' in str(exc_info.getrepr()) else: assert 0
def setup_contextional_groups(self, nodeid, location): __tracebackhide__ = True for group in location._group._setup_ancestry: if group not in group._helper._level_stack: if self.showlongtestinfo: group._pytest_writer = self start_time = time() try: group._setup_group() except: # handle error during group setup excinfo = ExceptionInfo() stop_time = time() nodeid = nodeid.split("::")[0] + "::" nodeid += group._inline_description location = group._last_location keywords = {} outcome = "failed" longrepr = excinfo.getrepr() when = "setup" sections = [] duration = stop_time - start_time context_lines = [ "Context:", "", ] context_lines += str(location).split("\n") context_lines[-1] = ">" + context_lines[-1][1:] entry = ReprEntry(context_lines, None, None, None, "long") if hasattr(longrepr, "chain"): reprtraceback = longrepr.chain[0][0] else: reprtraceback = longrepr.reprtraceback reprtraceback.reprentries.insert(0, entry) report = TestReport( nodeid, location, keywords, outcome, longrepr, when, sections, duration, ) self.pytest_runtest_logreport(report)
def _repr_failure_py( self, excinfo: ExceptionInfo[BaseException], style: "Optional[_TracebackStyle]" = None, ) -> TerminalRepr: from _pytest.fixtures import FixtureLookupError if isinstance(excinfo.value, ConftestImportFailure): excinfo = ExceptionInfo(excinfo.value.excinfo) if isinstance(excinfo.value, fail.Exception): if not excinfo.value.pytrace: style = "value" if isinstance(excinfo.value, FixtureLookupError): return excinfo.value.formatrepr() if self.config.getoption("fulltrace", False): style = "long" else: tb = _pytest._code.Traceback([excinfo.traceback[-1]]) self._prunetraceback(excinfo) if len(excinfo.traceback) == 0: excinfo.traceback = tb if style == "auto": style = "long" # XXX should excinfo.getrepr record all data and toterminal() process it? if style is None: if self.config.getoption("tbstyle", "auto") == "short": style = "short" else: style = "long" if self.config.getoption("verbose", 0) > 1: truncate_locals = False else: truncate_locals = True # excinfo.getrepr() formats paths relative to the CWD if `abspath` is False. # It is possible for a fixture/test to change the CWD while this code runs, which # would then result in the user seeing confusing paths in the failure message. # To fix this, if the CWD changed, always display the full absolute path. # It will be better to just always display paths relative to invocation_dir, but # this requires a lot of plumbing (#6428). try: abspath = Path(os.getcwd()) != self.config.invocation_params.dir except OSError: abspath = True return excinfo.getrepr( funcargs=True, abspath=abspath, showlocals=self.config.getoption("showlocals", False), style=style, tbfilter=False, # pruned already, or in --fulltrace mode. truncate_locals=truncate_locals, )
def __init__(self, exception, when="setup"): self.when = when self.start = time.time() self.stop = time.time() # We need to generate a traceback to continue. ExceptionInfo # calls sys.exc_info() internally try: raise exception except Exception: self.excinfo = ExceptionInfo()
def test_repr_traceback_with_unicode(style, encoding): msg = u"☹" if encoding is not None: msg = msg.encode(encoding) try: raise RuntimeError(msg) except RuntimeError: e_info = ExceptionInfo.from_current() formatter = FormattedExcinfo(style=style) repr_traceback = formatter.repr_traceback(e_info) assert repr_traceback is not None
def __init__(self, func, when): #: context of invocation: one of "setup", "call", #: "teardown", "memocollect" self.when = when self.start = time() try: self.result = func() except KeyboardInterrupt: self.stop = time() raise except: self.excinfo = ExceptionInfo() self.stop = time()
def test_repr_source_failing_fullsource(self, monkeypatch) -> None: pr = FormattedExcinfo() try: 1 / 0 except ZeroDivisionError: excinfo = ExceptionInfo.from_current() with monkeypatch.context() as m: m.setattr(_pytest._code.Code, "fullsource", property(lambda self: None)) repr = pr.repr_excinfo(excinfo) assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" assert repr.chain[0][0].reprentries[0].lines[0] == "> ???"
def from_call(cls, func, when, reraise=None): #: context of invocation: one of "setup", "call", #: "teardown", "memocollect" start = time() excinfo = None try: result = func() except: # noqa excinfo = ExceptionInfo.from_current() if reraise is not None and excinfo.errisinstance(reraise): raise result = None stop = time() return cls(start=start, stop=stop, when=when, result=result, excinfo=excinfo)
def from_call(cls, func, when, reraise=None) -> "CallInfo": #: context of invocation: one of "setup", "call", #: "teardown", "memocollect" start = time() excinfo = None try: result = func() except: # noqa excinfo = ExceptionInfo.from_current() if reraise is not None and excinfo.errisinstance(reraise): raise result = None stop = time() return cls(start=start, stop=stop, when=when, result=result, excinfo=excinfo)
def _repr_failure_py( self, excinfo: ExceptionInfo[BaseException], style=None, ) -> Union[str, ReprExceptionInfo, ExceptionChainRepr, FixtureLookupErrorRepr]: if isinstance(excinfo.value, ConftestImportFailure): excinfo = ExceptionInfo(excinfo.value.excinfo) if isinstance(excinfo.value, fail.Exception): if not excinfo.value.pytrace: style = "value" if isinstance(excinfo.value, FixtureLookupError): return excinfo.value.formatrepr() if self.config.getoption("fulltrace", False): style = "long" else: tb = _pytest._code.Traceback([excinfo.traceback[-1]]) self._prunetraceback(excinfo) if len(excinfo.traceback) == 0: excinfo.traceback = tb if style == "auto": style = "long" # XXX should excinfo.getrepr record all data and toterminal() process it? if style is None: if self.config.getoption("tbstyle", "auto") == "short": style = "short" else: style = "long" if self.config.getoption("verbose", 0) > 1: truncate_locals = False else: truncate_locals = True try: os.getcwd() abspath = False except OSError: abspath = True return excinfo.getrepr( funcargs=True, abspath=abspath, showlocals=self.config.getoption("showlocals", False), style=style, tbfilter=False, # pruned already, or in --fulltrace mode. truncate_locals=truncate_locals, )
def repr_failure(self, excinfo): import doctest if excinfo.errisinstance( (doctest.DocTestFailure, doctest.UnexpectedException)): doctestfailure = excinfo.value example = doctestfailure.example test = doctestfailure.test filename = test.filename if test.lineno is None: lineno = None else: lineno = test.lineno + example.lineno + 1 message = excinfo.type.__name__ reprlocation = ReprFileLocation(filename, lineno, message) checker = _get_checker() report_choice = _get_report_choice( self.config.getoption("doctestreport")) if lineno is not None: lines = doctestfailure.test.docstring.splitlines(False) # add line numbers to the left of the error message lines = [ "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines) ] # trim docstring error lines to 10 lines = lines[example.lineno - 9:example.lineno + 1] else: lines = [ 'EXAMPLE LOCATION UNKNOWN, not showing all tests of that example' ] indent = '>>>' for line in example.source.splitlines(): lines.append('??? %s %s' % (indent, line)) indent = '...' if excinfo.errisinstance(doctest.DocTestFailure): lines += checker.output_difference(example, doctestfailure.got, report_choice).split("\n") else: inner_excinfo = ExceptionInfo(excinfo.value.exc_info) lines += [ "UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value) ] lines += traceback.format_exception(*excinfo.value.exc_info) return ReprFailDoctest(reprlocation, lines) else: return super(DoctestItem, self).repr_failure(excinfo)
def from_call( cls, func: "Callable[[], TResult]", when: "Literal['collect', 'setup', 'call', 'teardown']", reraise: Optional[ Union[Type[BaseException], Tuple[Type[BaseException], ...]] ] = None, ) -> "CallInfo[TResult]": """Call func, wrapping the result in a CallInfo. :param func: The function to call. Called without arguments. :param when: The phase in which the function is called. :param reraise: Exception or exceptions that shall propagate if raised by the function, instead of being wrapped in the CallInfo. """ excinfo = None start = timing.time() precise_start = timing.perf_counter() try: result: Optional[TResult] = func() except BaseException: excinfo = ExceptionInfo.from_current() if reraise is not None and isinstance(excinfo.value, reraise): raise result = None # use the perf counter precise_stop = timing.perf_counter() duration = precise_stop - precise_start stop = timing.time() return cls( start=start, stop=stop, duration=duration, when=when, result=result, excinfo=excinfo, _ispytest=True, )
def pytest_runtest_makereport(item, call): "Log all assert messages to default logger with error level" # Nothing happened if call.when == "call": pause = topotest_extra_config["pause_after"] else: pause = False if call.excinfo is None and call.when == "call": try: check_for_memleaks() except: call.excinfo = ExceptionInfo() if call.excinfo is None: error = False else: parent = item.parent modname = parent.module.__name__ # Treat skips as non errors, don't pause after if call.excinfo.typename != "AssertionError": pause = False error = False logger.info( 'assert skipped at "{}/{}": {}'.format( modname, item.name, call.excinfo.value ) ) else: error = True # Handle assert failures parent._previousfailed = item # pylint: disable=W0212 logger.error( 'assert failed at "{}/{}": {}'.format( modname, item.name, call.excinfo.value ) ) # We want to pause, if requested, on any error not just test cases # (e.g., call.when == "setup") if not pause: pause = topotest_extra_config["pause_after"] # (topogen) Set topology error to avoid advancing in the test. tgen = get_topogen() if tgen is not None: # This will cause topogen to report error on `routers_have_failure`. tgen.set_error("{}/{}".format(modname, item.name)) if error and topotest_extra_config["shell_on_error"]: for router in tgen.routers(): pause = True tgen.net[router].runInWindow(os.getenv("SHELL", "bash")) if error and topotest_extra_config["vtysh_on_error"]: for router in tgen.routers(): pause = True tgen.net[router].runInWindow("vtysh") if error and topotest_extra_config["mininet_on_error"]: tgen.mininet_cli() if pause: try: user = raw_input('Testing paused, "pdb" to debug, "Enter" to continue: ') except NameError: user = input('Testing paused, "pdb" to debug, "Enter" to continue: ') if user.strip() == "pdb": pdb.set_trace()
def pytest_runtest_makereport(item, call): "Log all assert messages to default logger with error level" # Nothing happened if call.when == "call": pause = topotest_extra_config["pause"] else: pause = False if call.excinfo is None and call.when == "call": try: check_for_memleaks() except: call.excinfo = ExceptionInfo() title = "unset" if call.excinfo is None: error = False else: parent = item.parent modname = parent.module.__name__ # Treat skips as non errors, don't pause after if call.excinfo.typename == "Skipped": pause = False error = False logger.info('test skipped at "{}/{}": {}'.format( modname, item.name, call.excinfo.value)) else: error = True # Handle assert failures parent._previousfailed = item # pylint: disable=W0212 logger.error('test failed at "{}/{}": {}'.format( modname, item.name, call.excinfo.value)) title = "{}/{}".format(modname, item.name) # We want to pause, if requested, on any error not just test cases # (e.g., call.when == "setup") if not pause: pause = (topotest_extra_config["pause_on_error"] or topotest_extra_config["pause"]) # (topogen) Set topology error to avoid advancing in the test. tgen = get_topogen() if tgen is not None: # This will cause topogen to report error on `routers_have_failure`. tgen.set_error("{}/{}".format(modname, item.name)) commander = Commander("pytest") isatty = sys.stdout.isatty() error_cmd = None if error and topotest_extra_config["vtysh_on_error"]: error_cmd = commander.get_exec_path(["vtysh"]) elif error and topotest_extra_config["shell_on_error"]: error_cmd = os.getenv("SHELL", commander.get_exec_path(["bash"])) if error_cmd: is_tmux = bool(os.getenv("TMUX", "")) is_screen = not is_tmux and bool(os.getenv("STY", "")) is_xterm = not is_tmux and not is_screen and bool( os.getenv("DISPLAY", "")) channel = None win_info = None wait_for_channels = [] wait_for_procs = [] # Really would like something better than using this global here. # Not all tests use topogen though so get_topogen() won't work. for node in Mininet.g_mnet_inst.hosts.values(): pause = True if is_tmux: channel = ("{}-{}".format(os.getpid(), Commander.tmux_wait_gen) if not isatty else None) Commander.tmux_wait_gen += 1 wait_for_channels.append(channel) pane_info = node.run_in_window( error_cmd, new_window=win_info is None, background=True, title="{} ({})".format(title, node.name), name=title, tmux_target=win_info, wait_for=channel, ) if is_tmux: if win_info is None: win_info = pane_info elif is_xterm: assert isinstance(pane_info, subprocess.Popen) wait_for_procs.append(pane_info) # Now wait on any channels for channel in wait_for_channels: logger.debug("Waiting on TMUX channel %s", channel) commander.cmd_raises( [commander.get_exec_path("tmux"), "wait", channel]) for p in wait_for_procs: logger.debug("Waiting on TMUX xterm process %s", p) o, e = p.communicate() if p.wait(): logger.warning("xterm proc failed: %s:", proc_error(p, o, e)) if error and topotest_extra_config["cli_on_error"]: # Really would like something better than using this global here. # Not all tests use topogen though so get_topogen() won't work. if Mininet.g_mnet_inst: cli(Mininet.g_mnet_inst, title=title, background=False) else: logger.error("Could not launch CLI b/c no mininet exists yet") while pause and isatty: try: user = raw_input( 'PAUSED, "cli" for CLI, "pdb" to debug, "Enter" to continue: ') except NameError: user = input( 'PAUSED, "cli" for CLI, "pdb" to debug, "Enter" to continue: ') user = user.strip() if user == "cli": cli(Mininet.g_mnet_inst) elif user == "pdb": pdb.set_trace() elif user: print('Unrecognized input: "%s"' % user) else: break
def repr_failure( # type: ignore[override] self, excinfo: ExceptionInfo[BaseException], ) -> Union[str, TerminalRepr]: import doctest failures: Optional[Sequence[Union[doctest.DocTestFailure, doctest.UnexpectedException]]] = None if isinstance(excinfo.value, (doctest.DocTestFailure, doctest.UnexpectedException)): failures = [excinfo.value] elif isinstance(excinfo.value, MultipleDoctestFailures): failures = excinfo.value.failures if failures is None: return super().repr_failure(excinfo) reprlocation_lines = [] for failure in failures: example = failure.example test = failure.test filename = test.filename if test.lineno is None: lineno = None else: lineno = test.lineno + example.lineno + 1 message = type(failure).__name__ # TODO: ReprFileLocation doesn't expect a None lineno. reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type] checker = _get_checker() report_choice = _get_report_choice( self.config.getoption("doctestreport")) if lineno is not None: assert failure.test.docstring is not None lines = failure.test.docstring.splitlines(False) # add line numbers to the left of the error message assert test.lineno is not None lines = [ "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines) ] # trim docstring error lines to 10 lines = lines[max(example.lineno - 9, 0):example.lineno + 1] else: lines = [ "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example" ] indent = ">>>" for line in example.source.splitlines(): lines.append(f"??? {indent} {line}") indent = "..." if isinstance(failure, doctest.DocTestFailure): lines += checker.output_difference(example, failure.got, report_choice).split("\n") else: inner_excinfo = ExceptionInfo.from_exc_info(failure.exc_info) lines += [ "UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value) ] lines += [ x.strip("\n") for x in traceback.format_exception(*failure.exc_info) ] reprlocation_lines.append((reprlocation, lines)) return ReprFailDoctest(reprlocation_lines)
def toterminal(self, tw): for exc_info, item in self.reprs: tw.sep('_ ', item.name, red=True, bold=True) (item.repr_failure(ExceptionInfo(exc_info)).toterminal(tw))
def test_excinfo_for_later(): e = ExceptionInfo.for_later() assert "for raises" in repr(e) assert "for raises" in str(e)
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))