"""Pytest plugin to capture unhandled exception"""
from __future__ import annotations

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))
