From bb2249c5746ea9fa30575b0d803f4bfbae6831c7 Mon Sep 17 00:00:00 2001 From: CPD Date: Wed, 19 Mar 2025 17:24:51 +0100 Subject: [PATCH] Add options for displaying errors --- cpdctrl_gui/init.py | 17 +++++++++++------ cpdctrl_gui/ui/main_window.py | 3 +-- cpdctrl_gui/ui/widgets/settings/app_settings.py | 2 ++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cpdctrl_gui/init.py b/cpdctrl_gui/init.py index 80d3032..c601102 100644 --- a/cpdctrl_gui/init.py +++ b/cpdctrl_gui/init.py @@ -48,6 +48,7 @@ logging.basicConfig( ) log = logging.getLogger(__name__) +# Mechanism to catch, log and display uncaught exceptions # This is taken from: # https://timlehr.com/2018/01/python-exception-hooks-with-qt-message-box/index.html handler = logging.StreamHandler(stream=sys.stdout) @@ -59,7 +60,8 @@ def show_exception_box(log_msg): """ if QtWidgets.QApplication.instance() is not None: errorbox = QtWidgets.QMessageBox() - errorbox.setText("Oops. An unexpected error occured:\n{0}".format(log_msg)) + errorbox.setWindowTitle("An Unexpected Error Occurred") + errorbox.setText(log_msg) errorbox.exec() else: log.debug("No QApplication instance available.") @@ -67,8 +69,9 @@ def show_exception_box(log_msg): class UncaughtHook(QtCore.QObject): _exception_caught = QtCore.pyqtSignal(object) - def __init__(self, *args, **kwargs): + def __init__(self, *args, show_traceback=False, **kwargs): super(UncaughtHook, self).__init__(*args, **kwargs) + self.show_traceback = show_traceback # this registers the exception_hook() function as hook with the Python interpreter sys.excepthook = self.exception_hook @@ -85,12 +88,14 @@ class UncaughtHook(QtCore.QObject): sys.__excepthook__(exc_type, exc_value, exc_traceback) else: exc_info = (exc_type, exc_value, exc_traceback) - log_msg = '\n'.join([''.join(traceback.format_tb(exc_traceback)), - '{0}: {1}'.format(exc_type.__name__, exc_value)]) + log_msg = f"{exc_type.__name__}: {exc_value}\n" + if self.show_traceback: + log_msg += "\n".join(traceback.format_tb(exc_traceback)) log.critical(f"Uncaught exception:\n {log_msg}", exc_info=exc_info) # trigger message box show self._exception_caught.emit(log_msg) -# create a global instance of our class to register the hook -qt_exception_hook = UncaughtHook() +if AppConfig.MAIN_CFG.get_or("error_show_dialog", True): + # create a global instance of our class to register the hook + qt_exception_hook = UncaughtHook(show_traceback=AppConfig.MAIN_CFG.get_or("error_stack_trace", False)) diff --git a/cpdctrl_gui/ui/main_window.py b/cpdctrl_gui/ui/main_window.py index 4bd3002..f2dd1d5 100644 --- a/cpdctrl_gui/ui/main_window.py +++ b/cpdctrl_gui/ui/main_window.py @@ -331,9 +331,8 @@ class MainWindow(QMainWindow): if self.leddev is None: raise RuntimeError("No led control device selected") self.idle_stop() - if not (self.vmdev_connected() and self.leddev_connected()): - raise RuntimeError(f"Can not start measurement, a device lost connection.") + raise KeyError("Exception for testing") name = self.w_measurement_settings.get_value("name") script = self.w_measurement_settings.get_value("led_script") flush_after = self.w_measurement_settings.get_value("flush_after") diff --git a/cpdctrl_gui/ui/widgets/settings/app_settings.py b/cpdctrl_gui/ui/widgets/settings/app_settings.py index 6c459b2..3aca189 100644 --- a/cpdctrl_gui/ui/widgets/settings/app_settings.py +++ b/cpdctrl_gui/ui/widgets/settings/app_settings.py @@ -35,4 +35,6 @@ class AppSettings(QWidget): w_idle_dt.setMaximum(200000) w_idle_dt.setSingleStep(10) self.w_form.add_form_row("idle_update_interval_s", "Device Connection Check Interval (s)", 30, w_plot_dt, "How often to check whether the devices are still connected.\nApplies only when not in a measurement.") + self.w_form.add_form_row("error_show_dialog", "Show Dialog on Error", True, QCheckBox(), "Whether to show a dialog window when uncaught errors occur\nLeave this on.") + self.w_form.add_form_row("error_stack_trace", "Stacktrace in errors", False, QCheckBox(), "Whether to show the call stack in unexpected error messages")