Source code for msl.qt.exceptions

"""
Exception handling.
"""
import traceback as tb

from . import Qt
from . import QtWidgets
from . import application
from . import prompt
from .utils import logger  # noqa: logger not defined in __all__
from .utils import save_image


[docs]def excepthook(exctype, value, traceback): """Displays unhandled exceptions in a :class:`QtWidgets.QMessageBox`. See :func:`sys.excepthook` for more details. To implement the :func:`excepthook` in your own application include the following: .. code-block:: python import sys from msl import qt sys.excepthook = qt.excepthook """ class ErrorDialog(QtWidgets.QDialog): def __init__(self): super(ErrorDialog, self).__init__(None, Qt.WindowType.WindowCloseButtonHint) # add a prefix to the title bar w = app.activeWindow() prefix = 'MSL' if w is None or not w.windowTitle() else w.windowTitle() self.setWindowTitle(prefix + ' || Unhandled Exception') self.setSizeGripEnabled(True) self.icon_label = QtWidgets.QLabel() critical_icon = app.style().standardIcon(QtWidgets.QStyle.StandardPixmap.SP_MessageBoxCritical) largest_size = critical_icon.availableSizes()[-1] self.icon_label.setPixmap(critical_icon.pixmap(largest_size)) self.error_label = QtWidgets.QLabel(value.__class__.__name__ + ':\n\n' + str(value)) self.error_label.setWordWrap(True) self.ok_button = QtWidgets.QPushButton('Close') self.ok_button.clicked.connect(self.close) # noqa: clicked.connect self.ok_button.setToolTip('Close') self.screenshot_button = QtWidgets.QPushButton('Screenshot') self.screenshot_button.clicked.connect(self.save_screenshot) # noqa: clicked.connect self.screenshot_button.setToolTip('Save a screenshot of this window') self.copy_button = QtWidgets.QPushButton('Copy') self.copy_button.clicked.connect(self.copy_to_clipboard) # noqa: clicked.connect self.copy_button.setToolTip('Copy the error message to the system clipboard') self.show_details_button = QtWidgets.QPushButton('Hide details...') self.show_details_button.clicked.connect(self.show_hide_details) # noqa: clicked.connect self.show_details_button.setToolTip('Show less information') self.detailed_textedit = QtWidgets.QTextEdit() self.detailed_textedit.setText(details) self.detailed_textedit.setReadOnly(True) expanding = QtWidgets.QSizePolicy.Policy.Expanding label_layout = QtWidgets.QHBoxLayout() label_layout.addWidget(self.icon_label) label_layout.addWidget(self.error_label, alignment=Qt.AlignmentFlag.AlignLeft) label_layout.addSpacerItem(QtWidgets.QSpacerItem(1, 1, expanding, expanding)) button_layout = QtWidgets.QHBoxLayout() button_layout.addWidget(self.ok_button) button_layout.addWidget(self.screenshot_button) button_layout.addWidget(self.copy_button) button_layout.addWidget(self.show_details_button) button_layout.addSpacerItem(QtWidgets.QSpacerItem(1, 1, expanding, expanding)) layout = QtWidgets.QVBoxLayout() layout.addLayout(label_layout) layout.addLayout(button_layout) layout.addWidget(self.detailed_textedit, stretch=1) self.setLayout(layout) def save_screenshot(self): filename = prompt.save(filters='Images (*.png *.jpg *.jpeg *.bmp)') if filename: save_image(self, filename) def show_hide_details(self): if self.detailed_textedit.isVisible(): self.detailed_textedit.hide() self.show_details_button.setText('Show details...') self.show_details_button.setToolTip('Show more information') self.adjustSize() else: self.detailed_textedit.show() self.show_details_button.setText('Hide details...') self.show_details_button.setToolTip('Show less information') def copy_to_clipboard(self): app.clipboard().setText(self.detailed_textedit.toPlainText()) details = ''.join(tb.format_exception(exctype, value, traceback)) logger.error(details) # ensure that a QApplication exists app = application() dialog = ErrorDialog() dialog.raise_() dialog.exec()