fix(bec_signal_proxy): ensure argless emissions are replayed on unblock

This commit is contained in:
2026-08-05 02:00:21 +02:00
committed by Jan Wyzula
parent 656e3b5458
commit 0da3907b1a
2 changed files with 66 additions and 3 deletions
+9 -3
View File
@@ -31,6 +31,7 @@ class BECSignalProxy(SignalProxy):
def __init__(self, *args, rateLimit=25, timeout=10.0, **kwargs):
super().__init__(*args, rateLimit=rateLimit, **kwargs)
self._blocking = False
self._pending = False
self.old_args = None
self.new_args = None
@@ -56,6 +57,7 @@ class BECSignalProxy(SignalProxy):
"""Receive signal, store the args and call signalReceived from the parent class if not blocked"""
self.new_args = args
if self.blocked is True:
self._pending = True
return
self.blocked = True
self.old_args = args
@@ -65,12 +67,16 @@ class BECSignalProxy(SignalProxy):
@SafeSlot()
def unblock_proxy(self):
"""Unblock the proxy, and call the signalReceived method in case there was an update of the args."""
"""
Unblock the proxy and replay emissions that arrived while it was blocked.
"""
if self.blocked:
self._timer.stop()
self.blocked = False
if self.new_args != self.old_args:
self.signalReceived(*self.new_args)
if self._pending:
self._pending = False
if self.new_args == () or self.new_args != self.old_args:
self.signalReceived(*self.new_args)
@SafeSlot()
def _timeout_unblock(self):
@@ -122,3 +122,60 @@ def test_bec_signal_proxy_timeout(qtbot, dap_combo_box):
# The second value "samz" should have been forwarded after auto-unblocking
assert proxy_container == [(("samx",),), (("samz",),)]
def test_bec_signal_proxy_replays_argless_emissions_on_unblock(qtbot):
"""Emissions of an argument-less signal that arrive while the proxy is blocked must be
replayed on unblock: their args tuple is identical to the forwarded one, so an
args-comparison alone would silently drop them (the DAP-fit-never-arrives e2e flake:
one missed dap_response blocked the proxy, and every update emitted during the scan
coalesced into nothing)."""
from qtpy.QtCore import QObject, Signal
class _Src(QObject):
sig = Signal()
src = _Src()
calls = []
proxy = BECSignalProxy(src.sig, rateLimit=25, slot=lambda *_: calls.append(1), timeout=10.0)
src.sig.emit() # forwarded; proxy blocks awaiting unblock_proxy
qtbot.waitUntil(lambda: len(calls) == 1)
assert proxy.blocked is True
src.sig.emit() # coalesces while blocked - identical (empty) args
proxy.unblock_proxy()
# the coalesced emission is replayed instead of being dropped
qtbot.waitUntil(lambda: len(calls) == 2)
assert proxy.blocked is True # blocked again by the replayed emission
# no pending emission this time: unblocking must not replay anything
proxy.unblock_proxy()
qtbot.wait(150)
assert len(calls) == 2
assert proxy.blocked is False
proxy.cleanup()
def test_bec_signal_proxy_still_drops_identical_args_on_unblock(qtbot):
"""Emissions whose arguments equal the already-forwarded ones stay coalesced on
unblock - only argument-less signals are replayed unconditionally."""
from qtpy.QtCore import QObject, Signal
class _Src(QObject):
sig = Signal(str)
src = _Src()
calls = []
proxy = BECSignalProxy(src.sig, rateLimit=25, slot=lambda *a: calls.append(a), timeout=10.0)
src.sig.emit("samx") # forwarded; proxy blocks
qtbot.waitUntil(lambda: len(calls) == 1)
src.sig.emit("samx") # identical args while blocked
proxy.unblock_proxy()
qtbot.wait(150)
assert len(calls) == 1 # unchanged args are not replayed
assert proxy.blocked is False
proxy.cleanup()