Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing PyQt to silence exceptions occurring in slots

Tags:

python

pyqt

As far as I can see, if an exception occurs in a slot under PyQt, the exception is printed to screen, but not bubbled. This creates a problem in my testing strategy, because if an exception occurs in a slot, I will not see the test fail.

Here is an example:

import sys from PyQt4 import QtGui, QtCore  class Test(QtGui.QPushButton):     def __init__(self, parent=None):         QtGui.QWidget.__init__(self, parent)         self.setText("hello")         self.connect(self, QtCore.SIGNAL("clicked()"), self.buttonClicked)      def buttonClicked(self):         print "clicked"         raise Exception("wow")  app=QtGui.QApplication(sys.argv) t=Test() t.show() try:     app.exec_() except:     print "exiting" 

Note how the exception never quits the program.

Is there a way to work around this problem?

like image 683
Stefano Borini Avatar asked Sep 11 '13 12:09

Stefano Borini


People also ask

Is PyQt thread safe?

Is PyQt thread safe? Remarks# While some parts of the Qt framework are thread safe, much of it is not. The Qt C++ documentation provides a good overview of which classes are reentrant (can be used to instantiate objects in multiple threads).

What is signal and slot in PyQt5?

PyQt5 has a unique signal and slot mechanism to deal with events. Signals and slots are used for communication between objects. A signal is emitted when a particular event occurs. A slot can be any Python callable.

What is a signal in PyQt terminology?

Signals are notifications emitted by widgets when something happens. That something can be any number of things, from pressing a button, to the text of an input box changing, to the text of the window changing. Many signals are initiated by user action, but this is not a rule.


2 Answers

Can create a decorator that wraps PyQt' new signal/slot decorators and provides exception handling for all slots. Can also override QApplication::notify to catch uncaught C++ exceptions.

import sys import traceback import types from functools import wraps from PyQt4 import QtGui, QtCore  def MyPyQtSlot(*args):     if len(args) == 0 or isinstance(args[0], types.FunctionType):         args = []     @QtCore.pyqtSlot(*args)     def slotdecorator(func):         @wraps(func)         def wrapper(*args, **kwargs):             try:                 func(*args)             except:                 print "Uncaught Exception in slot"                 traceback.print_exc()         return wrapper      return slotdecorator  class Test(QtGui.QPushButton):     def __init__(self, parent=None):         QtGui.QWidget.__init__(self, parent)         self.setText("hello")         self.clicked.connect(self.buttonClicked)      @MyPyQtSlot("bool")     def buttonClicked(self, checked):         print "clicked"         raise Exception("wow")  class MyApp(QtGui.QApplication):     def notify(self, obj, event):         isex = False         try:             return QtGui.QApplication.notify(self, obj, event)         except Exception:             isex = True             print "Unexpected Error"             print traceback.format_exception(*sys.exc_info())             return False         finally:             if isex:                 self.quit()  app = MyApp(sys.argv)  t=Test() t.show() try:     app.exec_() except:     print "exiting" 
like image 181
jlujan Avatar answered Sep 19 '22 09:09

jlujan


You could exit the application with a non-zero return code to indicate that an exception has occurred.
You can catch all exception by installing a global exception hook. I added an example below, but you probably will want to adjust it to your needs.

import sys from PyQt4 import QtGui, QtCore  class Test(QtGui.QPushButton):     def __init__(self, parent=None):         QtGui.QWidget.__init__(self, parent)         self.setText("hello")         self.connect(self, QtCore.SIGNAL("clicked()"), self.buttonClicked)      def buttonClicked(self):         print "clicked"         raise Exception("wow")  sys._excepthook = sys.excepthook def exception_hook(exctype, value, traceback):     sys._excepthook(exctype, value, traceback)     sys.exit(1) sys.excepthook = exception_hook  app=QtGui.QApplication(sys.argv) t=Test() t.show() try:     app.exec_() except:     print "exiting" 
like image 41
aukaost Avatar answered Sep 20 '22 09:09

aukaost