Created a new error handler and dialog class

This commit is contained in:
Veronica K. B. Olsen
2020-08-17 20:32:52 +02:00
parent 7df2f83202
commit 35ed4a1c8d
+109 -44
View File
@@ -25,56 +25,113 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
def formatHtmlErrMsg(exType, exValue, exTrace): from PyQt5.QtCore import Qt
"""Generates a HTML version of an exception. from PyQt5.QtWidgets import (
""" qApp, QDialog, QGridLayout, QStyle, QPlainTextEdit, QLabel,
try: QDialogButtonBox
)
class NWErrorMessage(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent=parent)
self.mainBox = QGridLayout()
self.msgIcon = QLabel()
self.msgIcon.setPixmap(
qApp.style().standardIcon(QStyle.SP_MessageBoxCritical).pixmap(64, 64)
)
self.msgHead = QLabel()
self.msgHead.setOpenExternalLinks(True)
self.msgHead.setWordWrap(True)
self.msgBody = QPlainTextEdit()
self.msgBody.setReadOnly(True)
self.btnBox = QDialogButtonBox(QDialogButtonBox.Close)
self.btnBox.rejected.connect(self._doClose)
self.mainBox.addWidget(self.msgIcon, 0, 0, 2, 1, Qt.AlignTop)
self.mainBox.addWidget(self.msgHead, 0, 1, 1, 1, Qt.AlignTop)
self.mainBox.addWidget(self.msgBody, 1, 1, 1, 1)
self.mainBox.addWidget(self.btnBox, 2, 0, 1, 2)
self.mainBox.setSpacing(16)
self.setLayout(self.mainBox)
# self.setIcon(QMessageBox.Critical)
self.setMinimumWidth(500)
self.setMinimumHeight(300)
self.setSizeGripEnabled(True)
self.resize(800, 400)
return
def setMessage(self, exType, exValue, exTrace):
"""Generate a message and append session data, error info and
error traceback.
"""
import sys import sys
from traceback import format_tb from traceback import format_tb
from nw import __issuesurl__, __version__ from nw import __issuesurl__, __version__
from PyQt5.Qt import PYQT_VERSION_STR from PyQt5.Qt import PYQT_VERSION_STR
from PyQt5.QtCore import QT_VERSION_STR, QSysInfo from PyQt5.QtCore import QT_VERSION_STR, QSysInfo
fmtTrace = "" self.msgHead.setText((
for trEntry in format_tb(exTrace): "<p>An unhandled error has been encountered.</p>"
for trLine in trEntry.split("\n"): "<p>Please report this error by submitting an issue report on "
stripLine = trLine.lstrip(" ") "GitHub, providing a description and including the error "
nIndent = len(trLine) - len(stripLine) "message and traceback shown below.</p>"
fmtTrace += "&nbsp;"*nIndent + stripLine + "<br>" "<p>URL: <a href='{issueUrl}'>{issueUrl}</a></p>"
).format(
issueUrl = __issuesurl__,
))
try: try:
kernelVersion = QSysInfo.kernelVersion() kernelVersion = QSysInfo.kernelVersion()
except Exception: except Exception:
kernelVersion = "Unknown" kernelVersion = "Unknown"
theMessage = ( try:
"<p>Please report this error by submitting an issue report on " self.msgBody.setPlainText((
"GitHub, providing a description and this error message. " "Environment:\n"
"URL: &lt;{issueUrl}&gt;.</p>" "novelWriter Version: {nwVersion}\n"
"<p><b>Environment</b><br>Version: {nwVersion}, OS: {osType} ({osKernel}), " "Host OS: {osType} ({osKernel})\n"
"Python: {pyVersion} ({pyHexVer:#x}), Qt: {qtVers}, PyQt: {pyqtVers}</p>" "Python: {pyVersion} ({pyHexVer:#x})\n"
"<p><b>Error Type</b><br>{exType}: {exMessage}</p>" "Qt: {qtVers}, PyQt: {pyqtVers}\n"
"<p><b>Traceback</b><br>{exTrace}</p>" "\n"
).format( "{exType}:\n{exMessage}\n"
nwVersion = __version__, "\n"
osType = sys.platform, "Traceback:\n{exTrace}\n"
osKernel = kernelVersion, ).format(
pyVersion = sys.version.split()[0], nwVersion = __version__,
pyHexVer = sys.hexversion, osType = sys.platform,
qtVers = QT_VERSION_STR, osKernel = kernelVersion,
pyqtVers = PYQT_VERSION_STR, pyVersion = sys.version.split()[0],
issueUrl = __issuesurl__, pyHexVer = sys.hexversion,
exType = exType.__name__, qtVers = QT_VERSION_STR,
exMessage = str(exValue), pyqtVers = PYQT_VERSION_STR,
exTrace = fmtTrace exType = exType.__name__,
) exMessage = str(exValue),
exTrace = "\n".join(format_tb(exTrace)),
))
except Exception:
self.msgBody.setPlainText("Failed to generate error report ...")
return theMessage return
except Exception as e: ##
return "Could not generate error message.<br>%s" % str(e) # Slots
##
return "Could not generate error message." def _doClose(self):
"""Close the dialog.
"""
self.close()
return
# END Class NWErrorMessage
def exceptionHandler(exType, exValue, exTrace): def exceptionHandler(exType, exValue, exTrace):
@@ -83,10 +140,10 @@ def exceptionHandler(exType, exValue, exTrace):
import logging import logging
from traceback import print_tb from traceback import print_tb
from nw import CONFIG from nw import CONFIG
from PyQt5.QtWidgets import qApp, QErrorMessage from PyQt5.QtWidgets import qApp
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.error("%s: %s" % (exType.__name__, str(exValue))) logger.critical("%s: %s" % (exType.__name__, str(exValue)))
print_tb(exTrace) print_tb(exTrace)
if not CONFIG.showGUI: if not CONFIG.showGUI:
@@ -103,14 +160,22 @@ def exceptionHandler(exType, exValue, exTrace):
logger.warning("Could not find main GUI window so cannot open error dialog") logger.warning("Could not find main GUI window so cannot open error dialog")
return return
errMsg = QErrorMessage(nwGUI) errMsg = NWErrorMessage(nwGUI)
errMsg.setWindowTitle("Unhandled Error") errMsg.setMessage(exType, exValue, exTrace)
errMsg.resize(800, 400) errMsg.exec_()
errMsg.showMessage((
"<h3>An unhandled error has been encountered</h3>%s" try:
) % formatHtmlErrMsg(exType, exValue, exTrace)) # Try a controlled shudown
nwGUI.closeProject(isYes=True)
nwGUI.closeMain()
logger.critical("Emergency shutdown successful")
except Exception as e:
logger.error("Could not close the project before exiting.")
logger.error(str(e))
qApp.exit(1)
except Exception as e: except Exception as e:
logger.error(str(e)) logger.critical(str(e))
return return