Merge pull request #378 from vkbo/exceptions

Exception Handling
This commit is contained in:
Veronica K. Berglyd Olsen
2020-08-02 19:17:20 +02:00
committed by GitHub
4 changed files with 147 additions and 24 deletions
+35 -23
View File
@@ -34,6 +34,7 @@ from os import path, remove, rename
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QErrorMessage from PyQt5.QtWidgets import QApplication, QErrorMessage
from nw.error import exceptionHandler
from nw.config import Config from nw.config import Config
__package__ = "nw" __package__ = "nw"
@@ -249,11 +250,12 @@ def main(sysArgs=None):
if errorData: if errorData:
errApp = QApplication([]) errApp = QApplication([])
errMsg = QErrorMessage() errMsg = QErrorMessage()
errMsg.setMinimumWidth(500) errMsg.resize(500, 300)
errMsg.setMinimumHeight(300)
errMsg.showMessage(( errMsg.showMessage((
"ERROR: novelWriter cannot start due to the following issues:<br><br>" "<h3>A critical error has been encountered</h3>"
"&nbsp;-&nbsp;%s<br><br>Exiting." "<p>novelWriter cannot start due to the following issues:<p>"
"<p>&nbsp;-&nbsp;%s</p>"
"<p>Shutting down ...</p>"
) % ( ) % (
"<br>&nbsp;-&nbsp;".join(errorData) "<br>&nbsp;-&nbsp;".join(errorData)
)) ))
@@ -276,34 +278,44 @@ def main(sysArgs=None):
nwApp.setWindowIcon(QIcon(CONFIG.appIcon)) nwApp.setWindowIcon(QIcon(CONFIG.appIcon))
nwApp.setOrganizationDomain(__domain__) nwApp.setOrganizationDomain(__domain__)
# We try to catch critical errors while setting up the main GUI
# by wrapping the main GUI in a try/except structure. This will
# not catch all exceptions for other parts of the application.
# For all other unhandled exceptions, we use a custom exception
# handler that pops a dialog box with the error message.
sys.excepthook = exceptionHandler
try: try:
nwGUI = GuiMain() nwGUI = GuiMain()
sys.exit(nwApp.exec_()) sys.exit(nwApp.exec_())
except Exception: except Exception:
# novelWriter has crashed!
from traceback import print_tb, format_tb
eInfo = sys.exc_info() from traceback import print_tb
logger.critical("%s: %s" % (eInfo[0].__name__, eInfo[1])) from nw.error import formatHtmlErrMsg
print_tb(eInfo[2])
del nwApp exType, exValue, exTrace = sys.exc_info()
errApp = QApplication([]) logger.critical("%s: %s" % (exType.__name__, str(exValue)))
errMsg = QErrorMessage() print_tb(exTrace)
errMsg.setWindowTitle("Critical Error")
errMsg.setMinimumWidth(500)
errMsg.setMinimumHeight(300)
errMsg.showMessage((
"<h3>novelWriter has encountered a critical error!</h3>"
"<p><b>%s:</b><br>%s</p>"
"<p><b>Traceback:</b><br>%s</p>"
"<p>Shutting down ...</p>"
) % (eInfo[0].__name__, eInfo[1], "<br>".join(format_tb(eInfo[2]))))
errApp.exec_()
del eInfo try:
del nwApp
errApp = QApplication([])
errMsg = QErrorMessage()
errMsg.setWindowTitle("Critical Error")
errMsg.resize(800, 400)
errMsg.showMessage((
"<h3>A critical error has been encountered</h3>"
"%s"
"<p>Shutting down ...</p>"
) % formatHtmlErrMsg(exType, exValue, exTrace))
errApp.exec_()
except Exception as e:
logger.critical("Could not create error message dialog.")
logger.critical(str(e))
sys.exit(1) sys.exit(1)
+111
View File
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
"""novelWriter Init
novelWriter Exception Handling
==================================
Error handling functions
File History:
Created: 2020-08-02 [0.10.2]
This file is a part of novelWriter
Copyright 2020, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
def formatHtmlErrMsg(exType, exValue, exTrace):
"""Generates a HTML version of an exception.
"""
try:
import sys
from traceback import format_tb
from nw import __issuesurl__, __version__
from PyQt5.Qt import PYQT_VERSION_STR
from PyQt5.QtCore import QT_VERSION_STR, QSysInfo
fmtTrace = ""
for trEntry in format_tb(exTrace):
for trLine in trEntry.split("\n"):
stripLine = trLine.lstrip(" ")
nIndent = len(trLine) - len(stripLine)
fmtTrace += "&nbsp;"*nIndent + stripLine + "<br>"
theMessage = (
"<p>Please report this error by submitting an issue report on "
"GitHub, providing a description and this error message. "
"URL: &lt;{issueUrl}&gt;.</p>"
"<p><b>Environment</b><br>Version: {nwVersion}, OS: {osType} ({osKernel}),"
"Python: {pyVersion} ({pyHexVer:#x}), Qt: {qtVers}, PyQt: {pyqtVers}</p>"
"<p><b>Error Type</b><br>{exType}: {exMessage}</p>"
"<p><b>Traceback</b><br>{exTrace}</p>"
).format(
nwVersion = __version__,
osType = sys.platform,
osKernel = QSysInfo.kernelVersion(),
pyVersion = sys.version.split()[0],
pyHexVer = sys.hexversion,
qtVers = QT_VERSION_STR,
pyqtVers = PYQT_VERSION_STR,
issueUrl = __issuesurl__,
exType = exType.__name__,
exMessage = str(exValue),
exTrace = fmtTrace
)
return theMessage
except Exception as e:
return "Could not generate error message.<br>%s" % str(e)
return "Could not generate error message."
def exceptionHandler(exType, exValue, exTrace):
"""Function to catch unhandled global exceptions.
"""
import logging
from traceback import print_tb, format_tb
from nw import CONFIG
from PyQt5.QtWidgets import qApp, QApplication, QErrorMessage, QMessageBox
logger = logging.getLogger(__name__)
logger.error("%s: %s" % (exType.__name__, str(exValue)))
print_tb(exTrace)
if not CONFIG.showGUI:
return
try:
nwGUI = None
for qWin in qApp.topLevelWidgets():
if qWin.objectName() == "GuiMain":
nwGUI = qWin
break
if nwGUI is None:
logger.warning("Could not find main GUI window so cannot open error dialog")
return
errMsg = QErrorMessage(nwGUI)
errMsg.setWindowTitle("Unhandled Error")
errMsg.resize(800, 400)
errMsg.showMessage((
"<h3>An unhandled error has been encountered</h3>%s"
) % formatHtmlErrMsg(exType, exValue, exTrace))
except Exception as e:
logger.error(str(e))
return
-1
View File
@@ -432,7 +432,6 @@ class GuiBuildNovel(QDialog):
def _buildPreview(self): def _buildPreview(self):
"""Build a preview of the project in the document viewer. """Build a preview of the project in the document viewer.
""" """
# Get Settings # Get Settings
fmtTitle = self.fmtTitle.text().strip() fmtTitle = self.fmtTitle.text().strip()
fmtChapter = self.fmtChapter.text().strip() fmtChapter = self.fmtChapter.text().strip()
+1
View File
@@ -56,6 +56,7 @@ class GuiMain(QMainWindow):
QMainWindow.__init__(self) QMainWindow.__init__(self)
logger.debug("Initialising GUI ...") logger.debug("Initialising GUI ...")
self.setObjectName("GuiMain")
self.mainConf = nw.CONFIG self.mainConf = nw.CONFIG
# Some runtime info useful for debugging # Some runtime info useful for debugging