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.config import config
|
||||||
from qutebrowser.network import networkmanager
|
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):
|
class BrowserPage(QWebPage):
|
||||||
@ -223,6 +224,9 @@ class BrowserPage(QWebPage):
|
|||||||
"""
|
"""
|
||||||
return ext in self._extension_handlers
|
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):
|
def extension(self, ext, opt, out):
|
||||||
"""Override QWebPage::extension to provide error pages.
|
"""Override QWebPage::extension to provide error pages.
|
||||||
|
|
||||||
@ -235,28 +239,11 @@ class BrowserPage(QWebPage):
|
|||||||
Handler return value.
|
Handler return value.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
try:
|
handler = self._extension_handlers[ext]
|
||||||
handler = self._extension_handlers[ext]
|
except KeyError:
|
||||||
except KeyError:
|
log.webview.warning("Extension {} not supported!".format(ext))
|
||||||
log.webview.warning("Extension {} not supported!".format(ext))
|
return super().extension(ext, opt, out)
|
||||||
return super().extension(ext, opt, out)
|
return handler(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
|
|
||||||
|
|
||||||
def javaScriptAlert(self, _frame, msg):
|
def javaScriptAlert(self, _frame, msg):
|
||||||
"""Override javaScriptAlert to use the statusbar."""
|
"""Override javaScriptAlert to use the statusbar."""
|
||||||
|
@ -35,7 +35,7 @@ from PyQt5.QtGui import QKeySequence, QColor
|
|||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
import qutebrowser
|
import qutebrowser
|
||||||
from qutebrowser.utils import qtutils
|
from qutebrowser.utils import qtutils, log
|
||||||
|
|
||||||
|
|
||||||
def elide(text, length):
|
def elide(text, length):
|
||||||
@ -494,3 +494,59 @@ def disabled_excepthook():
|
|||||||
# unchanged. Otherwise, we reset it.
|
# unchanged. Otherwise, we reset it.
|
||||||
if sys.excepthook is sys.__excepthook__:
|
if sys.excepthook is sys.__excepthook__:
|
||||||
sys.excepthook = old_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