Add a decorator to prevent Exceptions (to prevent segfaults).
This commit is contained in:
parent
5eef6d422d
commit
644dfe53e2
@ -30,7 +30,8 @@ from PyQt5.QtWebKitWidgets import QWebPage
|
||||
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.network import networkmanager
|
||||
from qutebrowser.utils import message, usertypes, log, http, jinja, qtutils
|
||||
from qutebrowser.utils import (message, usertypes, log, http, jinja, qtutils,
|
||||
utils)
|
||||
|
||||
|
||||
class BrowserPage(QWebPage):
|
||||
@ -223,6 +224,9 @@ class BrowserPage(QWebPage):
|
||||
"""
|
||||
return ext in self._extension_handlers
|
||||
|
||||
# WORKAROUND for:
|
||||
# http://www.riverbankcomputing.com/pipermail/pyqt/2014-August/034722.html
|
||||
@utils.prevent_exceptions(False, PYQT_VERSION < 0x50302)
|
||||
def extension(self, ext, opt, out):
|
||||
"""Override QWebPage::extension to provide error pages.
|
||||
|
||||
@ -235,28 +239,11 @@ class BrowserPage(QWebPage):
|
||||
Handler return value.
|
||||
"""
|
||||
try:
|
||||
try:
|
||||
handler = self._extension_handlers[ext]
|
||||
except KeyError:
|
||||
log.webview.warning("Extension {} not supported!".format(ext))
|
||||
return super().extension(ext, opt, out)
|
||||
return handler(opt, out)
|
||||
except: # pylint: disable=bare-except
|
||||
if PYQT_VERSION >= 0x50302:
|
||||
raise
|
||||
else:
|
||||
# WORKAROUND:
|
||||
#
|
||||
# Due to a bug in PyQt, exceptions inside extension() get
|
||||
# swallowed:
|
||||
# http://www.riverbankcomputing.com/pipermail/pyqt/2014-August/034722.html
|
||||
#
|
||||
# We used to re-raise the exception with a single-shot QTimer
|
||||
# here, but that lead to a strange proble with a KeyError with
|
||||
# some random jinja template stuff as content. For now, we only
|
||||
# log it, so it doesn't pass 100% silently.
|
||||
log.webview.exception("Error inside WebPage::extension")
|
||||
return False
|
||||
handler = self._extension_handlers[ext]
|
||||
except KeyError:
|
||||
log.webview.warning("Extension {} not supported!".format(ext))
|
||||
return super().extension(ext, opt, out)
|
||||
return handler(opt, out)
|
||||
|
||||
def javaScriptAlert(self, _frame, msg):
|
||||
"""Override javaScriptAlert to use the statusbar."""
|
||||
|
@ -35,7 +35,7 @@ from PyQt5.QtGui import QKeySequence, QColor
|
||||
import pkg_resources
|
||||
|
||||
import qutebrowser
|
||||
from qutebrowser.utils import qtutils
|
||||
from qutebrowser.utils import qtutils, log
|
||||
|
||||
|
||||
def elide(text, length):
|
||||
@ -494,3 +494,59 @@ def disabled_excepthook():
|
||||
# unchanged. Otherwise, we reset it.
|
||||
if sys.excepthook is sys.__excepthook__:
|
||||
sys.excepthook = old_excepthook
|
||||
|
||||
|
||||
class prevent_exceptions: # pylint: disable=invalid-name
|
||||
|
||||
"""Decorator to ignore and log exceptions.
|
||||
|
||||
This needs to be used for some places where PyQt segfaults on exceptions or
|
||||
silently ignores them.
|
||||
|
||||
We used to re-raise the exception with a single-shot QTimer in a similiar
|
||||
case, but that lead to a strange proble with a KeyError with some random
|
||||
jinja template stuff as content. For now, we only log it, so it doesn't
|
||||
pass 100% silently.
|
||||
|
||||
This could also be a function, but as a class (with a "wrong" name) it's
|
||||
much cleaner to implement.
|
||||
|
||||
Attributes:
|
||||
retval: The value to return in case of an exception.
|
||||
predicate: The condition which needs to be True to prevent exceptions
|
||||
"""
|
||||
|
||||
def __init__(self, retval, predicate=True):
|
||||
"""Save decorator arguments.
|
||||
|
||||
Gets called on parse-time with the decorator arguments.
|
||||
|
||||
Args:
|
||||
See class attributes.
|
||||
"""
|
||||
self.retval = retval
|
||||
self.predicate = predicate
|
||||
|
||||
def __call__(self, func):
|
||||
"""Gets called when a function should be decorated.
|
||||
|
||||
Args:
|
||||
func: The function to be decorated.
|
||||
|
||||
Return:
|
||||
The decorated function.
|
||||
"""
|
||||
if not self.predicate:
|
||||
return func
|
||||
|
||||
retval = self.retval
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except BaseException:
|
||||
log.misc.exception("Error in {}".format(func.__qualname__))
|
||||
return retval
|
||||
|
||||
return wrapper
|
||||
|
Loading…
Reference in New Issue
Block a user