-
-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Understanding PyQt and raising exceptions #25
Comments
Hi, Unfortunately both You can see some other workarounds here which might be a good fit for you particular application. Hope that helps, |
Thanks for the quick answer! from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import Qt
import sys
class ExceptionHandler(QtCore.QObject):
errorSignal = QtCore.pyqtSignal()
def __init__(self):
super(ExceptionHandler, self).__init__()
def handler(self, exctype, value, traceback):
self.errorSignal.emit()
sys._excepthook(exctype, value, traceback)
exceptionHandler = ExceptionHandler()
sys._excepthook = sys.excepthook
sys.excepthook = exceptionHandler.handler
def something():
print "ERROR ERROR ERROR"
class Test(QtGui.QPushButton):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setText("hello")
self.resize(300, 400)
self.clicked.connect(self.division)
def division(self):
0 / 0
if __name__ == '__main__':
app=QtGui.QApplication(sys.argv)
widget = Test()
widget.show()
exceptionHandler.errorSignal.connect(something)
app.exec_() My ExceptionHandler is a QObject cause I hoped to use qtbots wait signal and wait for errorSignal fired. Something like: def test_zero(self, qtbot):
qtbot.addWidget(self.widget)
self.widget.clicked.connect(self.widget.zeroDivide)
with qtbot.waitSignal(exceptionHandler.testSignal, timeout=1000) as blocker:
qtbot.mouseClick(self.widget, QtCore.Qt.LeftButton)
assert blocker.signal_triggered As far as I understand it qtbot (or pytest?!) overwrites the sys.excepthook. So my own rewrite doesnt work anymore. Any suggestions? |
Hi,
# pytestqt.plugin.py
@contextmanager
def capture_exceptions():
"""
Context manager that captures exceptions that happen insides its context,
and returns them as a list of (type, value, traceback) after the
context ends.
"""
result = []
def hook(type_, value, tback):
result.append((type_, value, tback))
sys.__excepthook__(type_, value, tback)
sys.excepthook = hook
try:
yield result
finally:
sys.excepthook = sys.__excepthook__
@pytest.yield_fixture
def qtbot(qapp):
"""
Fixture used to create a QtBot instance for using during testing.
Make sure to call addWidget for each top-level widget you create to ensure
that they are properly closed after the test ends.
"""
result = QtBot(qapp)
with capture_exceptions() as exceptions:
yield result
if exceptions:
pytest.fail(format_captured_exceptions(exceptions))
result._close() As you can see, it overwrites the hook so it can check if exceptions happened during testing. Do you plan to overwrite the hint: you can add syntax highlighting to your sample code when writing on GitHub by using fenced code blocks and adding the language in the first line like this:
Took the liberty and updated your post above. 😄 |
Hi, thanks for the hint! I keep it in mind for the next time 😄 The ini idea sounds good. I'am not sure if it will work for me, but it sounds good 😄 (I'am not that experienced with pytest nor testing at all...). If it's not that complicate to implement I opt for it. Cheers! |
Can you manually comment out the lines in @pytest.yield_fixture
def qtbot(qapp):
result = QtBot(qapp)
exceptions = []
#with capture_exceptions() as exceptions:
yield result
if exceptions:
pytest.fail(format_captured_exceptions(exceptions))
result._close() To see if that fits well with your code? If that's the case, I can implement the |
I changed the code in plugin.py to: @pytest.yield_fixture
def qtbot(request):
#"""
#Fixture used to create a QtBot instance for using during testing.
#Make sure to call addWidget for each top-level widget you create to ensure
#that they are properly closed after the test ends.
#"""
result = QtBot(request.config.qt_app_instance)
yield result
#with capture_exceptions() as exceptions:
#yield result
#if exceptions:
#pytest.fail(format_captured_exceptions(exceptions))
result._close() The following test runs like a charm: import pytest
import pytestqt
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import Qt
import sys
class ExceptionHandler(QtCore.QObject):
errorSignal = QtCore.pyqtSignal()
silentSignal = QtCore.pyqtSignal()
def __init__(self):
super(ExceptionHandler, self).__init__()
def handler(self, exctype, value, traceback):
self.errorSignal.emit()
print "ERROR CAPTURED"
sys._excepthook(exctype, value, traceback)
exceptionHandler = ExceptionHandler()
sys._excepthook = sys.excepthook
sys.excepthook = exceptionHandler.handler
class Test(QtGui.QPushButton):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setText("hello")
self.resize(300, 400)
self.clicked.connect(self.division)
def division(self):
0 / 0
class TestClass(object):
def setup_class(self):
self.widget = Test()
def teardown_class(self):
pass
def test_zero(self):
with pytest.raises(ZeroDivisionError):
self.widget.division()
def test_division(self, qtbot):
qtbot.addWidget(self.widget)
with qtbot.waitSignal(exceptionHandler.errorSignal, timeout=1000) as blocker:
qtbot.mouseClick(self.widget, QtCore.Qt.LeftButton)
assert blocker.signal_triggered
def test_silentSignal(self, qtbot):
qtbot.addWidget(self.widget)
with qtbot.waitSignal(exceptionHandler.silentSignal, timeout=1000) as blocker:
qtbot.mouseClick(self.widget, QtCore.Qt.LeftButton)
assert not blocker.signal_triggered |
Excellent! 😄 Thanks for bringing this up, I will implement this in #26. Cheers! |
Hi, I have a few problems understanding the behavior of PyQt and exception handling. Why is no exception raised when zeroDivide() is called by the button click? Is there another solution except to mark the test as expected to fail? Why is the test test_buttonClick2() started two times and test_testFail() just once?
The text was updated successfully, but these errors were encountered: