From 85ccd61dd808d763331533dd656eae4fa3df0470 Mon Sep 17 00:00:00 2001 From: Sofia Donato Ferreira Date: Thu, 30 Apr 2026 15:46:44 -0300 Subject: [PATCH] fix: cleanup timer in signal blocker from the correct thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the PySide6 documentation on QTimer: Qt uses the timer’s thread affinity to determine which thread will emit the timeout() signal. Because of this, you must start and stop the timer in its thread; Because of that, we need to schedule the stop invokation to run in the timer's parent thread. Signed-off-by: Sofia Donato Ferreira --- src/pytestqt/wait_signal.py | 12 +++++++++++- tests/test_wait_signal.py | 9 --------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/pytestqt/wait_signal.py b/src/pytestqt/wait_signal.py index da98228d..a76dc2ce 100644 --- a/src/pytestqt/wait_signal.py +++ b/src/pytestqt/wait_signal.py @@ -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 + ) def _get_timeout_error_message(self): """Subclasses have to implement this, returning an appropriate error message for a TimeoutError.""" diff --git a/tests/test_wait_signal.py b/tests/test_wait_signal.py index 72d00ed6..7502b919 100644 --- a/tests/test_wait_signal.py +++ b/tests/test_wait_signal.py @@ -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