-
-
Notifications
You must be signed in to change notification settings - Fork 70
Expand file tree
/
Copy pathexceptions.py
More file actions
140 lines (106 loc) · 3.74 KB
/
exceptions.py
File metadata and controls
140 lines (106 loc) · 3.74 KB
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import functools
import sys
import traceback
from contextlib import contextmanager
import pytest
from pytestqt.utils import get_marker
@contextmanager
def capture_exceptions():
"""
Context manager that captures exceptions that happen insides its context,
and returns them as a list of (type, value, traceback) after the
context ends.
"""
manager = _QtExceptionCaptureManager()
manager.start()
try:
yield manager.exceptions
finally:
manager.finish()
def _except_hook(type_, value, tback, exceptions=None):
"""Hook functions installed by _QtExceptionCaptureManager"""
exceptions.append((type_, value, tback))
sys.stderr.write(format_captured_exceptions([(type_, value, tback)]))
class _QtExceptionCaptureManager:
"""
Manages exception capture context.
"""
def __init__(self):
self.old_hook = None
self.exceptions = []
def start(self):
"""Start exception capturing by installing a hook into sys.excepthook
that records exceptions received into ``self.exceptions``.
"""
self.old_hook = sys.excepthook
sys.excepthook = functools.partial(_except_hook, exceptions=self.exceptions)
def finish(self):
"""Stop exception capturing, restoring the original hook.
Can be called multiple times.
"""
if self.old_hook is not None:
sys.excepthook = self.old_hook
self.old_hook = None
def fail_if_exceptions_occurred(self, when):
"""calls pytest.fail() with an informative message if exceptions
have been captured so far. Before pytest.fail() is called, also
finish capturing.
"""
if self.exceptions:
self.finish()
exceptions = self.exceptions
self.exceptions = []
prefix = "%s ERROR: " % when
msg = prefix + format_captured_exceptions(exceptions)
del exceptions[:] # Don't keep exceptions alive longer.
if hasattr(sys, "last_exc"):
sys.last_exc = None
pytest.fail(msg, pytrace=False)
def format_captured_exceptions(exceptions):
"""
Formats exceptions given as (type, value, traceback) into a string
suitable to display as a test failure.
"""
from io import StringIO
stream = StringIO()
stream.write("Exceptions caught in Qt event loop:\n")
sep = "_" * 80 + "\n"
stream.write(sep)
for exc_type, value, tback in exceptions:
traceback.print_exception(exc_type, value, tback, file=stream)
stream.write(sep)
return stream.getvalue()
def _is_exception_capture_enabled(item):
"""returns if exception capture is disabled for the given test item."""
disabled = get_marker(item, "qt_no_exception_capture") or item.config.getini(
"qt_no_exception_capture"
)
return not disabled
class TimeoutError(Exception):
"""
.. versionadded:: 2.1
Exception thrown by :class:`pytestqt.qtbot.QtBot` methods.
Access via ``qtbot.TimeoutError``.
"""
class ScreenshotError(Exception):
"""
.. versionadded:: 4.1
Exception thrown by :meth:`pytestqt.qtbot.QtBot.screenshot` if taking the
screenshot failed.
.. versionchanged:: 4.2
Access via ``qtbot.ScreenshotError``.
"""
class SignalEmittedError(Exception):
"""
.. versionadded:: 1.11
The exception thrown by :meth:`pytestqt.qtbot.QtBot.assertNotEmitted` if a
signal was emitted unexpectedly.
Access via ``qtbot.SignalEmittedError``.
"""
class CallbackCalledTwiceError(Exception):
"""
.. versionadded:: 3.1
The exception thrown by :meth:`pytestqt.qtbot.QtBot.waitCallback` if a
callback was called twice.
Access via ``qtbot.CallbackCalledTwiceError``.
"""