From 34c623bb604773558b5a0282386054ca1e2560d8 Mon Sep 17 00:00:00 2001 From: Thomas VINCENT Date: Fri, 23 Oct 2026 15:04:28 +0200 Subject: [PATCH 1/2] Make qtbot.assertNotEmitted accept a sequence of signals --- src/pytestqt/qtbot.py | 27 +++++++++++++++++++-------- src/pytestqt/wait_signal.py | 1 + 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/pytestqt/qtbot.py b/src/pytestqt/qtbot.py index 7127d34..9b6daa5 100644 --- a/src/pytestqt/qtbot.py +++ b/src/pytestqt/qtbot.py @@ -1,6 +1,6 @@ from __future__ import annotations -from collections.abc import Callable +from collections.abc import Callable, Sequence import contextlib from types import TracebackType import weakref @@ -505,15 +505,15 @@ def wait(self, ms: int) -> None: @contextlib.contextmanager def assertNotEmitted( - self, signal: SignalInstance, *, wait: int = 0 + self, signal: SignalInstance | Sequence[SignalInstance], wait: int = 0 ) -> Generator[None, None, None]: """ .. versionadded:: 1.11 - Make sure the given ``signal`` doesn't get emitted. + Make sure the given ``signal``s don't get emitted. :param wait: - How many milliseconds to wait to make sure the signal isn't emitted + How many milliseconds to wait to make sure the signals aren't emitted asynchronously. By default, this method returns immediately and only catches signals emitted inside the ``with``-block. @@ -522,10 +522,21 @@ def assertNotEmitted( .. note:: This method is also available as ``assert_not_emitted`` (pep-8 alias) """ - spy = SignalEmittedSpy(signal) - with spy, self.waitSignal(signal, timeout=wait, raising=False): - yield - spy.assert_not_emitted() + signals = list(signal) if isinstance(signal, Sequence) else [signal] + + with contextlib.ExitStack() as stack: + spies = [stack.enter_context(SignalEmittedSpy(sig)) for sig in signals] + with self.waitSignals(signals, timeout=wait, raising=False): + yield + + if len(spies) == 1: + spies[0].assert_not_emitted() + else: + emittedSignals = [spy.signal for spy in spies if spy.emitted] + if emittedSignals: + raise SignalEmittedError( + f"Signals {emittedSignals!r} unexpectedly emitted" + ) def waitUntil( self, callback: Callable[[], bool | None], *, timeout: int = 5000 diff --git a/src/pytestqt/wait_signal.py b/src/pytestqt/wait_signal.py index 5262fc7..9304435 100644 --- a/src/pytestqt/wait_signal.py +++ b/src/pytestqt/wait_signal.py @@ -600,6 +600,7 @@ def slot(self, *args): def __enter__(self): self.signal.connect(self.slot) + return self def __exit__(self, type, value, traceback): self.signal.disconnect(self.slot) From 1ecc34cb47b4009366b2567092932827c94dabca Mon Sep 17 00:00:00 2001 From: Thomas VINCENT Date: Fri, 23 Oct 2026 15:05:01 +0200 Subject: [PATCH 2/2] update test for multiple signals and fix fnmatch without assert --- tests/test_wait_signal.py | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/tests/test_wait_signal.py b/tests/test_wait_signal.py index 453f95a..44c11ee 100644 --- a/tests/test_wait_signal.py +++ b/tests/test_wait_signal.py @@ -1,7 +1,6 @@ from __future__ import annotations import functools -import fnmatch import pytest import sys @@ -1262,31 +1261,42 @@ def test_not_emitted(self, qtbot, signaller): with qtbot.assertNotEmitted(signaller.signal): pass + def test_not_emitted_signals(self, qtbot, signaller): + with qtbot.assertNotEmitted((signaller.signal, signaller.signal_2)): + pass + def test_emitted(self, qtbot, signaller): - with pytest.raises(SignalEmittedError) as excinfo: + with pytest.raises(SignalEmittedError, match="Signal .* unexpectedly emitted"): with qtbot.assertNotEmitted(signaller.signal): signaller.signal.emit() - fnmatch.fnmatchcase(str(excinfo.value), "Signal * unexpectedly emitted.") + def test_emitted_signals(self, qtbot, signaller): + with pytest.raises( + SignalEmittedError, match="Signals \\[.*, .*\\] unexpectedly emitted" + ): + with qtbot.assertNotEmitted([signaller.signal_args, signaller.signal_2]): + signaller.signal_args.emit("foo", 123) + signaller.signal_2.emit() def test_emitted_args(self, qtbot, signaller): - with pytest.raises(SignalEmittedError) as excinfo: + with pytest.raises( + SignalEmittedError, + match="Signal .* unexpectedly emitted with arguments \\['foo', 123\\]", + ): with qtbot.assertNotEmitted(signaller.signal_args): signaller.signal_args.emit("foo", 123) - fnmatch.fnmatchcase( - str(excinfo.value), - "Signal * unexpectedly emitted with arguments ['foo', 123]", - ) - def test_disconnected(self, qtbot, signaller): - with qtbot.assertNotEmitted(signaller.signal): + with qtbot.assertNotEmitted([signaller.signal, signaller.signal_2]): pass signaller.signal.emit() + signaller.signal_2.emit() def test_emitted_late(self, qtbot, signaller, timer): with pytest.raises(SignalEmittedError): - with qtbot.assertNotEmitted(signaller.signal, wait=100): + with qtbot.assertNotEmitted( + [signaller.signal, signaller.signal_2], wait=100 + ): timer.single_shot(signaller.signal, 10) def test_continues_when_emitted(self, qtbot, signaller, stop_watch):