编程语言
首页 > 编程语言> > PyQt事件循环和ipython中的异常

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