diff --git a/pytestqt/_tests/test_wait_signal.py b/pytestqt/_tests/test_wait_signal.py index addfbfbd..99cba4ea 100644 --- a/pytestqt/_tests/test_wait_signal.py +++ b/pytestqt/_tests/test_wait_signal.py @@ -217,9 +217,8 @@ def check(self, timeout, *delays): return StopWatch() -@pytest.mark.parametrize('multiple, raising', - [(True, True), (True, False), (False, True), - (False, False)]) +@pytest.mark.parametrize('multiple', [True, False]) +@pytest.mark.parametrize('raising', [True, False]) def test_wait_signals_handles_exceptions(qtbot, multiple, raising): """ Make sure waitSignal handles exceptions correctly. @@ -239,3 +238,30 @@ class TestException(Exception): with pytest.raises(TestException): with func(arg, timeout=10, raising=raising): raise TestException + + +@pytest.mark.parametrize('multiple', [True, False]) +@pytest.mark.parametrize('do_timeout', [True, False]) +def test_wait_twice(qtbot, single_shot, multiple, do_timeout): + """ + https://github.com/pytest-dev/pytest-qt/issues/69 + """ + signaller = Signaller() + + if multiple: + func = qtbot.waitSignals + arg = [signaller.signal] + else: + func = qtbot.waitSignal + arg = signaller.signal + + if do_timeout: + with func(arg, timeout=100): + single_shot(signaller.signal, 200) + with func(arg, timeout=100): + single_shot(signaller.signal, 200) + else: + with func(arg): + signaller.signal.emit() + with func(arg): + signaller.signal.emit() diff --git a/pytestqt/plugin.py b/pytestqt/plugin.py index 7ca92883..377b0e99 100644 --- a/pytestqt/plugin.py +++ b/pytestqt/plugin.py @@ -355,6 +355,12 @@ def __init__(self, timeout=1000, raising=False): self.timeout = timeout self.signal_triggered = False self.raising = raising + if timeout is None: + self._timer = None + else: + self._timer = QtCore.QTimer() + self._timer.setSingleShot(True) + self._timer.setInterval(timeout) def wait(self): """ @@ -367,13 +373,26 @@ def wait(self): return if self.timeout is None and not self._signals: raise ValueError("No signals or timeout specified.") - if self.timeout is not None: - QtCore.QTimer.singleShot(self.timeout, self._loop.quit) + if self._timer is not None: + self._timer.timeout.connect(self._quit_loop_by_timeout) + self._timer.start() self._loop.exec_() if not self.signal_triggered and self.raising: raise SignalTimeoutError("Didn't get signal after %sms." % self.timeout) + def _quit_loop_by_timeout(self): + self._loop.quit() + self._cleanup() + + def _cleanup(self): + if self._timer is not None: + try: + self._timer.timeout.disconnect(self._quit_loop_by_timeout) + except (TypeError, RuntimeError): + # already disconnected by Qt? + pass + def __enter__(self): return self @@ -426,6 +445,16 @@ def _quit_loop_by_signal(self): """ self.signal_triggered = True self._loop.quit() + self._cleanup() + + def _cleanup(self): + super(SignalBlocker, self)._cleanup() + for signal in self._signals: + try: + signal.disconnect(self._quit_loop_by_signal) + except (TypeError, RuntimeError): + # already disconnected by Qt? + pass class MultiSignalBlocker(_AbstractSignalBlocker):