mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-13 19:21:50 +02:00
fix(bec_signal_proxy): timeout for blocking implemented
This commit is contained in:
@ -5,28 +5,43 @@ analyse data. Requesting a new fit may lead to request piling up and an overall
|
||||
will allow you to decide by yourself when to unblock and execute the callback again."""
|
||||
|
||||
from pyqtgraph import SignalProxy
|
||||
from qtpy.QtCore import Signal, Slot
|
||||
from qtpy.QtCore import QTimer, Signal
|
||||
|
||||
from bec_widgets.qt_utils.error_popups import SafeSlot
|
||||
|
||||
|
||||
class BECSignalProxy(SignalProxy):
|
||||
"""Thin wrapper around the SignalProxy class to allow signal calls to be blocked, but args still being stored
|
||||
"""
|
||||
Thin wrapper around the SignalProxy class to allow signal calls to be blocked,
|
||||
but arguments still being stored.
|
||||
|
||||
Args:
|
||||
*args: Arguments to pass to the SignalProxy class
|
||||
rateLimit (int): The rateLimit of the proxy
|
||||
**kwargs: Keyword arguments to pass to the SignalProxy class
|
||||
*args: Arguments to pass to the SignalProxy class.
|
||||
rateLimit (int): The rateLimit of the proxy.
|
||||
timeout (float): The number of seconds after which the proxy automatically
|
||||
unblocks if still blocked. Default is 10.0 seconds.
|
||||
**kwargs: Keyword arguments to pass to the SignalProxy class.
|
||||
|
||||
Example:
|
||||
>>> proxy = BECSignalProxy(signal, rate_limit=25, slot=callback)"""
|
||||
>>> proxy = BECSignalProxy(signal, rate_limit=25, slot=callback)
|
||||
"""
|
||||
|
||||
is_blocked = Signal(bool)
|
||||
|
||||
def __init__(self, *args, rateLimit=25, **kwargs):
|
||||
def __init__(self, *args, rateLimit=25, timeout=10.0, **kwargs):
|
||||
super().__init__(*args, rateLimit=rateLimit, **kwargs)
|
||||
self._blocking = False
|
||||
self.old_args = None
|
||||
self.new_args = None
|
||||
|
||||
# Store timeout value (in seconds)
|
||||
self._timeout = timeout
|
||||
|
||||
# Create a single-shot timer for auto-unblocking
|
||||
self._timer = QTimer()
|
||||
self._timer.setSingleShot(True)
|
||||
self._timer.timeout.connect(self._timeout_unblock)
|
||||
|
||||
@property
|
||||
def blocked(self):
|
||||
"""Returns if the proxy is blocked"""
|
||||
@ -46,9 +61,22 @@ class BECSignalProxy(SignalProxy):
|
||||
self.old_args = args
|
||||
super().signalReceived(*args)
|
||||
|
||||
@Slot()
|
||||
self._timer.start(int(self._timeout * 1000))
|
||||
|
||||
@SafeSlot()
|
||||
def unblock_proxy(self):
|
||||
"""Unblock the proxy, and call the signalReceived method in case there was an update of the args."""
|
||||
self.blocked = False
|
||||
if self.new_args != self.old_args:
|
||||
self.signalReceived(*self.new_args)
|
||||
if self.blocked:
|
||||
self._timer.stop()
|
||||
self.blocked = False
|
||||
if self.new_args != self.old_args:
|
||||
self.signalReceived(*self.new_args)
|
||||
|
||||
@SafeSlot()
|
||||
def _timeout_unblock(self):
|
||||
"""
|
||||
Internal method called by the QTimer upon timeout. Unblocks the proxy
|
||||
automatically if it is still blocked.
|
||||
"""
|
||||
if self.blocked:
|
||||
self.unblock_proxy()
|
||||
|
@ -73,3 +73,52 @@ def test_bec_signal_proxy(qtbot, dap_combo_box):
|
||||
qtbot.wait(100)
|
||||
assert proxy.blocked is False
|
||||
assert proxy_container == [(("samx",),), (("samz",),)]
|
||||
|
||||
|
||||
def test_bec_signal_proxy_timeout(qtbot, dap_combo_box):
|
||||
"""
|
||||
Test that BECSignalProxy auto-unblocks after the specified timeout if no manual unblock
|
||||
occurs in the interim.
|
||||
"""
|
||||
proxy_container = []
|
||||
|
||||
def proxy_callback(*args):
|
||||
proxy_container.append(args)
|
||||
|
||||
# Create the proxy with a short 1-second timeout
|
||||
proxy = BECSignalProxy(
|
||||
dap_combo_box.x_axis_updated, rateLimit=25, slot=proxy_callback, timeout=1.0
|
||||
)
|
||||
|
||||
# Initially, ensure it's not blocked
|
||||
assert proxy.blocked is False
|
||||
|
||||
# Trigger the signal once (samx) -> the proxy should block
|
||||
dap_combo_box.x_axis = "samx"
|
||||
qtbot.waitSignal(dap_combo_box.x_axis_updated, timeout=1000)
|
||||
qtbot.wait(100)
|
||||
assert proxy.blocked is True
|
||||
# The first signal should be passed immediately to the callback
|
||||
assert proxy_container == [(("samx",),)]
|
||||
|
||||
# While still blocked, set another value (samz)
|
||||
dap_combo_box.x_axis = "samz"
|
||||
qtbot.waitSignal(dap_combo_box.x_axis_updated, timeout=1000)
|
||||
qtbot.wait(100)
|
||||
# Proxy is still blocked, so the callback shouldn't see "samz" yet
|
||||
assert len(proxy_container) == 1
|
||||
|
||||
# Wait just under 1 second -> should still be blocked
|
||||
qtbot.wait(700)
|
||||
assert proxy.blocked is True
|
||||
|
||||
# Wait a bit more than 1 s
|
||||
qtbot.wait(2000)
|
||||
|
||||
# Wait to catch the is_blocked signal that indicates it has unblocked
|
||||
qtbot.waitSignal(proxy.is_blocked, timeout=2000)
|
||||
# Now it should be unblocked
|
||||
assert proxy.blocked is False
|
||||
|
||||
# The second value "samz" should have been forwarded after auto-unblocking
|
||||
assert proxy_container == [(("samx",),), (("samz",),)]
|
||||
|
Reference in New Issue
Block a user