以下是说明问题的代码:
from PyQt4 import QtGui
app = QtGui.QApplication([])
dialog = QtGui.QDialog()
button = QtGui.QPushButton('I crash')
layout = QtGui.QHBoxLayout()
layout.addWidget(button)
dialog.setLayout(layout)
def crash(): raise Exception('Crash!')
button.clicked.connect(crash)
button.click()
print 'I should not happen'
当我运行它时,PyQt4为我处理错误。我的控制台显示“崩溃!”的堆栈跟踪在其中,我看到'我不应该发生'。
这没用,因为我已经交给了一个包含许多处理程序的大型应用程序,我需要将所有错误强加到我的脸上(并进入我的 - 自动化测试) 。每次我运行时,错误都会逃脱我的网络,并且它们需要过多且无用的尝试:除了块,在每个处理程序中,只是为了捕获它们。
换句话说,我希望良好的代码非常好,而且糟糕的代码非常糟糕。没有洗白。
如果已经提出这个问题,请道歉,但是当我进行电子搜索时,我自然会让成千上万的新手询问基本的错误处理问题(或者更糟糕的是,我让新手询问如何关闭他们任性的异常!;)< / p>
如何覆盖PyQt4的默认错误处理,以便我自己传播或记录错误?请不要回答sys.excepthook,它会捕获PyQt4 没有捕获的错误。
答案 0 :(得分:3)
这不是答案,你傻网站。停止强迫我们适应理想化线程模板的先入为主的概念。
未回答是使用我的测试框架setUp()来挂钩异常处理程序:
def setUp(self):
self.no_exceptions = True
def testExceptionHook(type, value, tback):
self.no_exceptions = False
sys.__excepthook__(type, value, tback)
sys.excepthook = testExceptionHook
如果说“self.no_exceptions = False”,我宁愿简单地说self.fail('')。但是,因为Python的单元测试库坚持抛出异常只是为了注册测试失败,并且因为PyQt坚持使用所有异常,所以我们遇到了死锁。
为了适应unittest.TestCase愚蠢的先入为主的理想化测试案例,我必须设置一个变量,然后在拆解中检测它:
def tearDown(self):
self.assertTrue(self.no_exceptions)
这仍然不理想,但至少它会迫使我花更多的时间来关注错误,而不是花时间在技术网站上抱怨它们。
根本问题:如何关闭PyQt的魔术错误处理程序? - 仍未得到答复......
答案 1 :(得分:2)
我认为答案是这不是PyQt
的“特征”,而是设计中固有的结果,让信号/插槽工作(请记住信号/插槽通信正在通过c ++层也是如此。
这很丑陋,但会对你的问题做一些并最终解决问题
from PyQt4 import QtGui
import time
app = QtGui.QApplication([])
class exception_munger(object):
def __init__(self):
self.flag = True
self.txt = ''
self.type = None
def indicate_fail(self,etype=None, txt=None):
self.flag = False
if txt is not None:
self.txt = txt
self.type = etype
def reset(self):
tmp_txt = self.txt
tmp_type = self.type
tmp_flag = self.flag
self.flag = True
self.txt = ''
self.type = None
return tmp_flag, tmp_type, tmp_txt
class e_manager():
def __init__(self):
self.old_hook = None
def __enter__(self):
em = exception_munger()
def my_hook(type, value, tback):
em.indicate_fail(type, value)
sys.__excepthook__(type, value, tback)
self.old_hook = sys.excepthook
sys.excepthook = my_hook
self.em = em
return self
def __exit__(self,*args,**kwargs):
sys.excepthook = self.old_hook
def mang_fac():
return e_manager()
def assert_dec(original_fun):
def new_fun(*args,**kwargs):
with mang_fac() as mf:
res = original_fun(*args, **kwargs)
flag, etype, txt = mf.em.reset()
if not flag:
raise etype(txt)
return res
return new_fun
@assert_dec
def my_test_fun():
dialog = QtGui.QDialog()
button = QtGui.QPushButton('I crash')
layout = QtGui.QHBoxLayout()
layout.addWidget(button)
dialog.setLayout(layout)
def crash():
time.sleep(1)
raise Exception('Crash!')
button.clicked.connect(crash)
button.click()
my_test_fun()
print 'should not happen'
这不会打印'不应该发生',并为您提供一些可以捕获自动化测试的东西(使用正确的异常类型)。
In [11]: Traceback (most recent call last):
File "/tmp/ipython2-3426rwB.py", line 68, in crash
Exception: Crash!
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-11-6ef4090ab3de> in <module>()
----> 1 execfile(r'/tmp/ipython2-3426rwB.py') # PYTHON-MODE
/tmp/ipython2-3426rwB.py in <module>()
/tmp/ipython2-3426rwB.py in new_fun(*args, **kwargs)
Exception: Crash!
In [12]:
堆栈跟踪被抬起,但您仍然可以读取打印出来的第一个。