This instance will be upgraded to Heptapod 0.21.0rc2 on 2021-04-16 at 11:00 UTC+2 (a few minutes of down time)

pytestcaptureexc.py 1.53 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
"""Pytest plugin to capture unhandled exception"""
from __future__ import print_function

try:
    from cStringIO import StringIO
except ImportError:
    try:
        from StringIO import StringIO
    except ImportError:
        from io import StringIO
import sys
import traceback

import pytest

class CaptureExcPlugin(object):
    """Capture unhandled exception (probably raised inside event loop)"""

    def pytest_addoption(self, parser):
        parser.addoption('--no-capture-exc', dest='capture_exc',
                         action='store_false', default=True,
                         help='Catch unhandled exception to report as error')

    def pytest_configure(self, config):
        options = config.known_args_namespace
        self.enabled = options.capture_exc

    @pytest.mark.hookwrapper
    def pytest_runtest_call(self, item):
        self._origexcepthook = sys.excepthook
        sys.excepthook = self._excepthook
        self._excepts = []
        try:
            yield
        finally:
            sys.excepthook = self._origexcepthook
            del self._origexcepthook
        if self._excepts:
            out = StringIO()
            print("%s uncaught exception(s):" % len(self._excepts), file=out)
            for exc_info in self._excepts:
                print(file=out)
                traceback.print_exception(*exc_info, file=out)
            del self._excepts[:]
            pytest.fail(out.getvalue(), pytrace=False)

    def _excepthook(self, type, value, traceback):
        self._excepts.append((type, value, traceback))