PyQt事件循环和ipython中的异常
作者:互联网
我有一个PyQt程序,其中显示了一些小部件和按钮.
我希望程序既可以作为独立的python实例运行,也可以在ipython环境中运行.在这种情况下,我在Jupyter控制台中使用以下魔术命令(以前,在启动ipython qtconsole时必须使用–gui = qt)
%pylab qt
为了使程序能够双向运行,我的主模块包含以下几行:
APP = QtGui.Qapplication.instance() # retrieves the ipython qt application if any
if APP is None:
APP = QtGui.QApplication(["foo"]) # create one if standalone execution
if __name__=='__main__':
APP.exec_() # Launch the event loop here in standalone mode
这是我的问题:事件循环生成的异常很难被用户检测到,因为它们会在后台控制台中弹出.我想捕获事件循环中发生的任何异常,并显示警告(例如QMainWindow状态栏中的实例,以使用户知道发生了异常).
我已经尝试了几种策略,但是PyQt和Ipython的内部机制之间似乎存在一种共谋,使这不可能:
>重新实现sys.excepthook(请参阅Preventing PyQt to silence exceptions occurring in slots):不起作用,因为ipython不断覆盖sys.excepthook
>检测IPython是否正在运行,然后使用IPYTHON.set_custom_exc(Opening an IPython shell on any (uncatched) exception):不幸的是,qt事件循环异常不会触发处理程序.
>覆盖QApplication.notify:运气不好,我打算在派生函数中调用的本机QApplication.notify函数不会引发异常,返回值(布尔值)也不会反映插槽的正确执行.这个线程的答案很有趣:How to log uncatched exceptions of a QApplication?,但是,该策略似乎在Qt c中有效,但是notify的python包装器只是将异常打印到控制台,而不是引发异常.
很长一段时间以来,这个问题一直困扰着我.有没有人有办法解决吗?
解决方法:
实际上,开发人员的答案为我指明了正确的方向:
问题在于,每次执行ipython单元时,都会对新的sys.excepthook进行猴子修补,一旦执行完成,就会将sys.excepthook还原到前一个(请参阅ipkernel / kernelapp.py).
因此,在普通的ipython单元指令中更改sys.excepthook不会更改在qt事件循环期间执行的excepthook.
一个简单的解决方案是在qt事件中对sys.excepthook进行monkeypatch:
from PyQt4 import QtCore, QtGui
import sys
from traceback import format_exception
def new_except_hook(etype, evalue, tb):
QtGui.QMessageBox.information(None,
str('error'),
''.join(format_exception(etype, evalue, tb)))
def patch_excepthook():
sys.excepthook = new_except_hook
TIMER = QtCore.QTimer()
TIMER.setSingleShot(True)
TIMER.timeout.connect(patch_excepthook)
TIMER.start()
关于此方法的一个好处是,它可以独立运行,也可以与ipython执行相同.
我猜想也可以想象通过在每个小部件的event_handler中调用patch_excepthook来根据不同的小部件触发异常来修补不同版本的new_except_hook.
标签:ipython,pyqt4,python,qt,qtconsole 来源: https://codeday.me/bug/20191026/1937122.html