Beispiel #1
0
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*',
        ])
Beispiel #2
0
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()
Beispiel #3
0
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)
Beispiel #5
0
    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
Beispiel #6
0
    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
Beispiel #7
0
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
Beispiel #8
0
 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()
Beispiel #9
0
 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,
     )
Beispiel #10
0
    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)
Beispiel #11
0
 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,
     )
Beispiel #12
0
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)
Beispiel #14
0
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
Beispiel #15
0
    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()
Beispiel #17
0
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
Beispiel #18
0
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
Beispiel #19
0
 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()
Beispiel #20
0
    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] == ">   ???"
Beispiel #21
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)
Beispiel #22
0
 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)
Beispiel #23
0
    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,
        )
Beispiel #24
0
 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)
Beispiel #25
0
    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,
        )
Beispiel #26
0
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()
Beispiel #27
0
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)
Beispiel #29
0
 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))
Beispiel #30
0
def test_excinfo_for_later():
    e = ExceptionInfo.for_later()
    assert "for raises" in repr(e)
    assert "for raises" in str(e)
Beispiel #31
0
def test_excinfo_for_later():
    e = ExceptionInfo.for_later()
    assert "for raises" in repr(e)
    assert "for raises" in str(e)
Beispiel #32
0
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))