Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/pytestqt/wait_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,17 @@ def _quit_loop_by_timeout(self):
def _cleanup(self):
# store timeout message before the data to construct it is lost
self._timeout_message = self._get_timeout_error_message()
self._timer.stop()

timer_meta = self._timer.metaObject()
timer_stop_signature = (
timer_meta.normalizedSignature("stop").data().decode("utf-8")
)
timer_stop_method = timer_meta.method(
timer_meta.indexOfMethod(timer_stop_signature)
)
timer_stop_method.invoke(
self._timer, qt_api.QtCore.Qt.ConnectionType.QueuedConnection
)
Comment on lines +72 to +82

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be simplified to:

Suggested change
timer_meta = self._timer.metaObject()
timer_stop_signature = (
timer_meta.normalizedSignature("stop").data().decode("utf-8")
)
timer_stop_method = timer_meta.method(
timer_meta.indexOfMethod(timer_stop_signature)
)
timer_stop_method.invoke(
self._timer, qt_api.QtCore.Qt.ConnectionType.QueuedConnection
)
assert qt_api.QtCore.QMetaObject.invokeMethod(self._timer, "stop", qt_api.QtCore.Qt.ConnectionType.QueuedConnection)

For some reason I don't quite understand, your approach seems to fail on PyQt, while this seems to work fine there too.

I think it's a good idea to add an assert for the return value, since calling this should never fail. If it does anyways, I think that should be a loud and not a silent failure. I'm surprised that PyQt actually does turn the failure into a RuntimeError on its own, I don't think that's guaranteed to happen everywhere though.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah your approach is way cleaner! I was afraid of the stop string not being sufficient for the invokeMethod call, since sometimes those methods require the full signature string (method index + method signature). Glad that's not the case here!


def _get_timeout_error_message(self):
"""Subclasses have to implement this, returning an appropriate error message for a TimeoutError."""
Expand Down
9 changes: 0 additions & 9 deletions tests/test_wait_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1425,15 +1425,6 @@ def test_thread(qtbot, capfd, _):
res = pytester.runpytest_subprocess("-x", "-s")
outcomes = res.parseoutcomes()

if outcomes.get("failed", 0) and check_stderr and qt_api.pytest_qt_api == "pyside6":
# The test succeeds on PyQt (unsure why!), but we can't check
# qt_api.pytest_qt_api at import time, so we can't use
# pytest.mark.xfail conditionally.
pytest.xfail(
"Qt error: QObject::killTimer: "
"Timers cannot be stopped from another thread"
)

res.assert_outcomes(passed=outcomes["passed"]) # no failed/error


Expand Down
Loading