PyQt事件循环中的异常和IPython

4
我有一个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 的内部机制之间存在阴谋,使此操作不可能。

这是一个长期困扰我的问题。有人有解决方案吗?


请尝试执行这个答案中提到的解决方案。 - ekhumoro
我忘记了这个问题:覆盖IPython将用作sys.excepthook的猴子补丁函数(如您的答案中建议的)也不起作用。实际上,使用qt选项的Ipython甚至会阻止qt事件循环调用sys.excepthook。我不明白IPython开发人员在捕获事件循环异常方面找到了什么可憎之处?! - Samuel
老实说,我认为在这里报告所有这些都是浪费时间:你需要向ipython开发人员反映此问题。 - ekhumoro
谢谢,我已经在ipython的github问题页面上发布了:https://github.com/ipython/ipython/issues/10057。同时我也注意到了这个相关的问题:http://stackoverflow.com/questions/26426419/ipython-gui-event-loop-exception-hook。 - Samuel
1个回答

5
实际上,开发人员的答案指引了我正确的方向:问题在于每次执行一个ipython单元格时,都会monkeypatch一个新的sys.excepthook,当执行结束时,就会将sys.excepthook恢复到之前的状态(请参见ipkernel/kernelapp.py)。
因此,在普通的ipython单元格指令中更改sys.excepthook不会改变在qt事件循环期间执行的excepthook。
一个简单的解决方法是在qt事件中monkeypatch sys.excepthook。
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执行。

我想可以通过在每个小部件的事件处理程序中调用patch_excepthook来猴子补丁不同版本的new_except_hook,具体取决于触发异常的小部件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接