def test_notification_manager_no_gui_with_threading(): """ Direct test of the notification manager. This does not test the integration with the gui, but test that exceptions and warnings from threads are correctly captured. """ def _warn(): time.sleep(0.01) warnings.showwarning('this is a warning', UserWarning, '', 0) def _raise(): time.sleep(0.01) with pytest.raises(PurposefulException): raise PurposefulException("this is an exception") if PY38_OR_HIGHER: previous_threading_exhook = threading.excepthook with notification_manager: notification_manager.records.clear() # save all of the events that get emitted store: List[Notification] = [] _append = lambda e: store.append(e) # lambda needed on py3.7 # noqa notification_manager.notification_ready.connect(_append) # Test exception inside threads if PY38_OR_HIGHER: # `threading.excepthook` available only for Python >= 3.8 assert (threading.excepthook == notification_manager.receive_thread_error) exception_thread = threading.Thread(target=_raise) exception_thread.start() time.sleep(0.02) if PY38_OR_HIGHER: threading.excepthook(sys.exc_info()) else: sys.excepthook(*sys.exc_info()) assert len(notification_manager.records) == 1 assert store[-1].type == 'error' # Test warning inside threads assert warnings.showwarning == notification_manager.receive_warning warning_thread = threading.Thread(target=_warn) warning_thread.start() time.sleep(0.02) assert len(notification_manager.records) == 2 assert store[-1].type == 'warning' # make sure we've restored the threading except hook if PY38_OR_HIGHER: assert threading.excepthook == previous_threading_exhook assert all(isinstance(x, Notification) for x in store)
def test_notification_manager_no_gui_with_threading(): """ Direct test of the notification manager. This does not test the integration with the gui, but test that exceptions and warnings from threads are correctly captured. """ def _warn(): warnings.showwarning('this is a warning', UserWarning, '', 0) def _raise(): with pytest.raises(PurposefulException): raise PurposefulException("this is an exception") previous_threading_exhook = threading.excepthook with notification_manager: notification_manager.records.clear() # save all of the events that get emitted store: List[Notification] = [] notification_manager.notification_ready.connect(store.append) # Test exception inside threads assert ( threading.excepthook == notification_manager.receive_thread_error) exception_thread = threading.Thread(target=_raise) exception_thread.start() exception_thread.join(timeout=DEFAULT_TIMEOUT_SECS) try: raise ValueError("a") except ValueError: threading.excepthook(sys.exc_info()) assert len(notification_manager.records) == 1 assert store[-1].type == 'error' # Test warning inside threads assert warnings.showwarning == notification_manager.receive_warning warning_thread = threading.Thread(target=_warn) warning_thread.start() warning_thread.join(timeout=DEFAULT_TIMEOUT_SECS) assert len(notification_manager.records) == 2 assert store[-1].type == 'warning' # make sure we've restored the threading except hook assert threading.excepthook == previous_threading_exhook assert all(isinstance(x, Notification) for x in store)
def test_excepthook_thread_None(self): # threading.excepthook called with thread=None: log the thread # identifier in this case. with support.captured_output("stderr") as stderr: try: raise ValueError("bug") except Exception as exc: args = threading.ExceptHookArgs([*sys.exc_info(), None]) threading.excepthook(args) stderr = stderr.getvalue().strip() self.assertIn(f'Exception in thread {threading.get_ident()}:\n', stderr) self.assertIn('Traceback (most recent call last):\n', stderr) self.assertIn(' raise ValueError("bug")', stderr) self.assertIn('ValueError: bug', stderr)