mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
fix: simplify AutoUpdate code thanks to threadpool executor in BEC Connector
This commit is contained in:
@ -67,7 +67,7 @@ class AutoUpdates:
|
|||||||
"""
|
"""
|
||||||
return self._default_fig
|
return self._default_fig
|
||||||
|
|
||||||
def run(self, msg):
|
def do_update(self, msg):
|
||||||
"""
|
"""
|
||||||
Run the update function if enabled.
|
Run the update function if enabled.
|
||||||
"""
|
"""
|
||||||
@ -76,20 +76,9 @@ class AutoUpdates:
|
|||||||
if msg.status != "open":
|
if msg.status != "open":
|
||||||
return
|
return
|
||||||
info = self.get_scan_info(msg)
|
info = self.get_scan_info(msg)
|
||||||
self.handler(info)
|
return self.handler(info)
|
||||||
|
|
||||||
def process_queue(self):
|
def get_selected_device(self, monitored_devices, selected_device):
|
||||||
"""
|
|
||||||
Process the message queue.
|
|
||||||
"""
|
|
||||||
while True:
|
|
||||||
msg = self.msg_queue.get()
|
|
||||||
if msg is self._shutdown_sentinel:
|
|
||||||
break
|
|
||||||
self.run(msg)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_selected_device(monitored_devices, selected_device):
|
|
||||||
"""
|
"""
|
||||||
Get the selected device for the plot. If no device is selected, the first
|
Get the selected device for the plot. If no device is selected, the first
|
||||||
device in the monitored devices list is selected.
|
device in the monitored devices list is selected.
|
||||||
@ -106,14 +95,11 @@ class AutoUpdates:
|
|||||||
Default update function.
|
Default update function.
|
||||||
"""
|
"""
|
||||||
if info.scan_name == "line_scan" and info.scan_report_devices:
|
if info.scan_name == "line_scan" and info.scan_report_devices:
|
||||||
self.simple_line_scan(info)
|
return self.simple_line_scan(info)
|
||||||
return
|
|
||||||
if info.scan_name == "grid_scan" and info.scan_report_devices:
|
if info.scan_name == "grid_scan" and info.scan_report_devices:
|
||||||
self.simple_grid_scan(info)
|
return self.simple_grid_scan(info)
|
||||||
return
|
|
||||||
if info.scan_report_devices:
|
if info.scan_report_devices:
|
||||||
self.best_effort(info)
|
return self.best_effort(info)
|
||||||
return
|
|
||||||
|
|
||||||
def simple_line_scan(self, info: ScanInfo) -> None:
|
def simple_line_scan(self, info: ScanInfo) -> None:
|
||||||
"""
|
"""
|
||||||
@ -123,12 +109,19 @@ class AutoUpdates:
|
|||||||
if not fig:
|
if not fig:
|
||||||
return
|
return
|
||||||
dev_x = info.scan_report_devices[0]
|
dev_x = info.scan_report_devices[0]
|
||||||
dev_y = self.get_selected_device(info.monitored_devices, self.gui.selected_device)
|
selected_device = self.gui.selected_device
|
||||||
|
dev_y = self.get_selected_device(info.monitored_devices, selected_device)
|
||||||
if not dev_y:
|
if not dev_y:
|
||||||
return
|
return
|
||||||
fig.clear_all()
|
fig.clear_all()
|
||||||
plt = fig.plot(x_name=dev_x, y_name=dev_y, label=f"Scan {info.scan_number} - {dev_y}")
|
fig.plot(
|
||||||
plt.set(title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y)
|
x_name=dev_x,
|
||||||
|
y_name=dev_y,
|
||||||
|
label=f"Scan {info.scan_number} - {dev_y}",
|
||||||
|
title=f"Scan {info.scan_number}",
|
||||||
|
x_label=dev_x,
|
||||||
|
y_label=dev_y,
|
||||||
|
)
|
||||||
|
|
||||||
def simple_grid_scan(self, info: ScanInfo) -> None:
|
def simple_grid_scan(self, info: ScanInfo) -> None:
|
||||||
"""
|
"""
|
||||||
@ -139,12 +132,18 @@ class AutoUpdates:
|
|||||||
return
|
return
|
||||||
dev_x = info.scan_report_devices[0]
|
dev_x = info.scan_report_devices[0]
|
||||||
dev_y = info.scan_report_devices[1]
|
dev_y = info.scan_report_devices[1]
|
||||||
dev_z = self.get_selected_device(info.monitored_devices, self.gui.selected_device)
|
selected_device = self.gui.selected_device
|
||||||
|
dev_z = self.get_selected_device(info.monitored_devices, selected_device)
|
||||||
fig.clear_all()
|
fig.clear_all()
|
||||||
plt = fig.plot(
|
fig.plot(
|
||||||
x_name=dev_x, y_name=dev_y, z_name=dev_z, label=f"Scan {info.scan_number} - {dev_z}"
|
x_name=dev_x,
|
||||||
|
y_name=dev_y,
|
||||||
|
z_name=dev_z,
|
||||||
|
label=f"Scan {info.scan_number} - {dev_z}",
|
||||||
|
title=f"Scan {info.scan_number}",
|
||||||
|
x_label=dev_x,
|
||||||
|
y_label=dev_y,
|
||||||
)
|
)
|
||||||
plt.set(title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y)
|
|
||||||
|
|
||||||
def best_effort(self, info: ScanInfo) -> None:
|
def best_effort(self, info: ScanInfo) -> None:
|
||||||
"""
|
"""
|
||||||
@ -154,17 +153,16 @@ class AutoUpdates:
|
|||||||
if not fig:
|
if not fig:
|
||||||
return
|
return
|
||||||
dev_x = info.scan_report_devices[0]
|
dev_x = info.scan_report_devices[0]
|
||||||
dev_y = self.get_selected_device(info.monitored_devices, self.gui.selected_device)
|
selected_device = self.gui.selected_device
|
||||||
|
dev_y = self.get_selected_device(info.monitored_devices, selected_device)
|
||||||
if not dev_y:
|
if not dev_y:
|
||||||
return
|
return
|
||||||
fig.clear_all()
|
fig.clear_all()
|
||||||
plt = fig.plot(x_name=dev_x, y_name=dev_y, label=f"Scan {info.scan_number} - {dev_y}")
|
fig.plot(
|
||||||
plt.set(title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y)
|
x_name=dev_x,
|
||||||
|
y_name=dev_y,
|
||||||
def shutdown(self):
|
label=f"Scan {info.scan_number} - {dev_y}",
|
||||||
"""
|
title=f"Scan {info.scan_number}",
|
||||||
Shutdown the auto update thread.
|
x_label=dev_x,
|
||||||
"""
|
y_label=dev_y,
|
||||||
self.msg_queue.put(self._shutdown_sentinel)
|
)
|
||||||
if self.auto_update_thread:
|
|
||||||
self.auto_update_thread.join()
|
|
||||||
|
@ -340,12 +340,6 @@ class BECGuiClient(RPCBase):
|
|||||||
with wait_for_server(self):
|
with wait_for_server(self):
|
||||||
return self._auto_updates
|
return self._auto_updates
|
||||||
|
|
||||||
def _shutdown_auto_updates(self):
|
|
||||||
if self._auto_updates_enabled:
|
|
||||||
if self._auto_updates is not None:
|
|
||||||
self._auto_updates.shutdown()
|
|
||||||
self._auto_updates = None
|
|
||||||
|
|
||||||
def _get_update_script(self) -> AutoUpdates | None:
|
def _get_update_script(self) -> AutoUpdates | None:
|
||||||
eps = imd.entry_points(group="bec.widgets.auto_updates")
|
eps = imd.entry_points(group="bec.widgets.auto_updates")
|
||||||
for ep in eps:
|
for ep in eps:
|
||||||
@ -389,18 +383,17 @@ class BECGuiClient(RPCBase):
|
|||||||
def _start_update_script(self) -> None:
|
def _start_update_script(self) -> None:
|
||||||
self._client.connector.register(MessageEndpoints.scan_status(), cb=self._handle_msg_update)
|
self._client.connector.register(MessageEndpoints.scan_status(), cb=self._handle_msg_update)
|
||||||
|
|
||||||
@staticmethod
|
def _handle_msg_update(self, msg: MessageObject) -> None:
|
||||||
def _handle_msg_update(msg: MessageObject, parent: BECGuiClient) -> None:
|
if self.auto_updates is not None:
|
||||||
if parent.auto_updates is not None:
|
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
parent._update_script_msg_parser(msg.value)
|
return self._update_script_msg_parser(msg.value)
|
||||||
|
|
||||||
def _update_script_msg_parser(self, msg: messages.BECMessage) -> None:
|
def _update_script_msg_parser(self, msg: messages.BECMessage) -> None:
|
||||||
if isinstance(msg, messages.ScanStatusMessage):
|
if isinstance(msg, messages.ScanStatusMessage):
|
||||||
if not self.gui_is_alive():
|
if not self.gui_is_alive():
|
||||||
return
|
return
|
||||||
if self._auto_updates_enabled:
|
if self._auto_updates_enabled:
|
||||||
self.auto_updates.msg_queue.put(msg)
|
return self.auto_updates.do_update(msg)
|
||||||
|
|
||||||
def _gui_post_startup(self):
|
def _gui_post_startup(self):
|
||||||
self._top_level["main"] = WidgetDesc(
|
self._top_level["main"] = WidgetDesc(
|
||||||
@ -415,6 +408,7 @@ class BECGuiClient(RPCBase):
|
|||||||
auto_updates = AutoUpdates(self._top_level["main"].widget)
|
auto_updates = AutoUpdates(self._top_level["main"].widget)
|
||||||
if auto_updates.create_default_dock:
|
if auto_updates.create_default_dock:
|
||||||
auto_updates.start_default_dock()
|
auto_updates.start_default_dock()
|
||||||
|
self._start_update_script()
|
||||||
self._auto_updates = auto_updates
|
self._auto_updates = auto_updates
|
||||||
self._do_show_all()
|
self._do_show_all()
|
||||||
self._gui_started_event.set()
|
self._gui_started_event.set()
|
||||||
@ -427,7 +421,6 @@ class BECGuiClient(RPCBase):
|
|||||||
logger.success("GUI starting...")
|
logger.success("GUI starting...")
|
||||||
self._startup_timeout = 5
|
self._startup_timeout = 5
|
||||||
self._gui_started_event.clear()
|
self._gui_started_event.clear()
|
||||||
self._start_update_script()
|
|
||||||
self._process, self._process_output_processing_thread = _start_plot_process(
|
self._process, self._process_output_processing_thread = _start_plot_process(
|
||||||
self._gui_id, self.__class__, self._client._service_config.config, logger=logger
|
self._gui_id, self.__class__, self._client._service_config.config, logger=logger
|
||||||
)
|
)
|
||||||
@ -512,4 +505,3 @@ class BECGuiClient(RPCBase):
|
|||||||
self._process_output_processing_thread.join()
|
self._process_output_processing_thread.join()
|
||||||
self._process.wait()
|
self._process.wait()
|
||||||
self._process = None
|
self._process = None
|
||||||
self._shutdown_auto_updates()
|
|
||||||
|
@ -219,9 +219,13 @@ class BECDockArea(BECWidget, QWidget):
|
|||||||
@property
|
@property
|
||||||
def selected_device(self) -> str:
|
def selected_device(self) -> str:
|
||||||
gui_id = QApplication.instance().gui_id
|
gui_id = QApplication.instance().gui_id
|
||||||
return self.client.connector.get(
|
auto_update_config = self.client.connector.get(
|
||||||
MessageEndpoints.gui_auto_update_config(gui_id)
|
MessageEndpoints.gui_auto_update_config(gui_id)
|
||||||
).selected_device
|
)
|
||||||
|
try:
|
||||||
|
return auto_update_config.selected_device
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def panels(self) -> dict[str, BECDock]:
|
def panels(self) -> dict[str, BECDock]:
|
||||||
|
@ -70,8 +70,7 @@ def test_client_utils_passes_client_config_to_server(bec_dispatcher):
|
|||||||
mixin.gui_is_alive.side_effect = [True]
|
mixin.gui_is_alive.side_effect = [True]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with mock.patch.object(mixin, "_start_update_script"):
|
yield mixin
|
||||||
yield mixin
|
|
||||||
finally:
|
finally:
|
||||||
mixin.close()
|
mixin.close()
|
||||||
|
|
||||||
@ -84,4 +83,3 @@ def test_client_utils_passes_client_config_to_server(bec_dispatcher):
|
|||||||
mock_start_plot.assert_called_once_with(
|
mock_start_plot.assert_called_once_with(
|
||||||
"gui_id", BECGuiClient, mixin._client._service_config.config, logger=mock.ANY
|
"gui_id", BECGuiClient, mixin._client._service_config.config, logger=mock.ANY
|
||||||
)
|
)
|
||||||
mixin._start_update_script.assert_called_once()
|
|
||||||
|
Reference in New Issue
Block a user