Reputation: 162
I'm trying to write a PyQt5 application that works in the system tray. The code sometimes raises exceptions, and I need to be able to catch them.
I would expect that when an exception occurs, the application's main event loop would be exited, so catching it should work as follows:
try:
application.exec()
except:
do_stuff()
However, when I run the following code, and press the "Raise" button, error caught!
is never output to the console, only the traceback:
from PyQt5 import QtWidgets, QtGui, QtCore
class ErrorApp():
def __init__(self):
# Init QApplication, QWidet and QMenu
self.app = QtWidgets.QApplication([])
self.widget = QtWidgets.QWidget()
self.menu = QtWidgets.QMenu("menu", self.widget)
# Add items to menu
self.menu_action_raise = self.menu.addAction("Raise")
self.menu_action_raise.triggered.connect(self.raise_error)
self.menu_action_exit = self.menu.addAction("Exit")
self.menu_action_exit.triggered.connect(self.app.exit)
# Create the tray app
self.tray = QtWidgets.QSystemTrayIcon(QtGui.QIcon("logo.png"), self.widget)
self.tray.setContextMenu(self.menu)
# Show app
self.tray.show()
def raise_error(self):
assert False
e = ErrorApp()
try:
e.app.exec()
except:
print("error caught!")
There are two similar questions, but their answers don't do what I need to do:
In question Grab any exception in PyQt, the OP wants to monitor the exceptions, not to exit the event loop.
In question
Preventing PyQt to silence exceptions occurring in slots, the accepted answer, involving a decorator, simply doesn't work; adding sys.exit(1)
to sys.excepthook
just closes the whole program, without printing error caught!
Upvotes: 16
Views: 11575
Reputation: 243897
You must use the exception and, if you want the event loop to end then you must call the quit()
(or exit()
) method.
import sys
import traceback
from PyQt5 import QtWidgets, QtGui, QtCore
class ErrorApp:
# ...
def raise_error(self):
assert False
def excepthook(exc_type, exc_value, exc_tb):
tb = "".join(traceback.format_exception(exc_type, exc_value, exc_tb))
print("error caught!:")
print("error message:\n", tb)
QtWidgets.QApplication.quit()
# or QtWidgets.QApplication.exit(0)
sys.excepthook = excepthook
e = ErrorApp()
ret = e.app.exec_()
print("event loop exited")
sys.exit(ret)
Output:
error caught!:
error message:
Traceback (most recent call last):
File "main.py", line 28, in raise_error
assert False
AssertionError
event loop exited
Upvotes: 30