1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
Exceptions in virtual methods
=============================
.. versionadded:: 1.1
.. note::
``PySide6 6.5.2+`` automatically captures exceptions that happen during the Qt event loop and
re-raises them when control is moved back to Python, so the functionality described here
does not work with ``PySide6`` (nor is necessary).
It is common in Qt programming to override virtual C++ methods to customize
behavior, like listening for mouse events, implement drawing routines, etc.
Fortunately, all Python bindings for Qt support overriding these virtual methods
naturally in your Python code:
.. code-block:: python
class MyWidget(QWidget):
# mouseReleaseEvent
def mouseReleaseEvent(self, ev):
print(f"mouse released at: {ev.pos()}")
In ``PyQt5`` and ``PyQt6``, exceptions in virtual methods will by default call
abort(), which will crash the interpreter. All other Qt wrappers will print the
exception stacktrace and return a default value back to C++/Qt (if a return
value is required).
This might be surprising for Python users which are used to exceptions
being raised at the calling point: For example, the following code will just
print a stack trace without raising any exception:
.. code-block:: python
class MyWidget(QWidget):
def mouseReleaseEvent(self, ev):
raise RuntimeError("unexpected error")
w = MyWidget()
QTest.mouseClick(w, QtCore.Qt.LeftButton)
To make testing Qt code less surprising, ``pytest-qt`` automatically
installs an exception hook which captures errors and fails tests when exceptions
are raised inside virtual methods, like this::
E Failed: Qt exceptions in virtual methods:
E ________________________________________________________________________________
E File "x:\pytest-qt\pytestqt\_tests\test_exceptions.py", line 14, in event
E raise RuntimeError('unexpected error')
E
E RuntimeError: unexpected error
Disabling the automatic exception hook
--------------------------------------
You can disable the automatic exception hook on individual tests by using a
``qt_no_exception_capture`` marker:
.. code-block:: python
@pytest.mark.qt_no_exception_capture
def test_buttons(qtbot):
...
Or even disable it for your entire project in your ``pytest.ini`` file:
.. code-block:: ini
[pytest]
qt_no_exception_capture = 1
This might be desirable if you plan to install a custom exception hook.
.. note::
Starting with ``PyQt5.5``, exceptions raised during virtual methods will
actually trigger an ``abort()``, crashing the Python interpreter. For this
reason, disabling exception capture in ``PyQt5.5+`` and ``PyQt6`` is not
recommended unless you install your own exception hook.
.. note::
As explained in the note at the top of the page, ``PySide6 6.5.2+`` has its own
exception capture mechanism, so this option has no effect when using this
library.
|