1
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2026-04-14 04:30:54 +02:00

Compare commits

...

10 Commits

Author SHA1 Message Date
semantic-release
2b75d5600a 2.45.13
Automatically generated by python-semantic-release
2025-12-17 13:52:45 +00:00
01c6e092b9 fix(scan queue): adjustments for changes to the pydantic model of the scan queue 2025-12-17 14:51:54 +01:00
semantic-release
ca6f355aac 2.45.12
Automatically generated by python-semantic-release
2025-12-16 12:37:06 +00:00
d876ca72bc fix(heatmap): more robust logic for fast and slow axis in grid scan 2025-12-16 13:36:17 +01:00
e0fd97616d fix(heatmap): flush image if config changes during scan 2025-12-16 13:36:17 +01:00
6af8a5cbfe fix(heatmap): grid scan image correctly map to scan positions 2025-12-16 13:36:17 +01:00
semantic-release
944e2cedf8 2.45.11
Automatically generated by python-semantic-release
2025-12-15 14:48:20 +00:00
cd11a6cce3 fix(waveform): support for AsyncMultiSignal 2025-12-15 15:47:26 +01:00
semantic-release
c98106e594 2.45.10
Automatically generated by python-semantic-release
2025-12-10 11:21:40 +00:00
04f1ff4fe7 fix(devices): minor fix to comply with new config helper in bec_lib 2025-12-10 12:20:48 +01:00
11 changed files with 355 additions and 172 deletions

View File

@@ -1,6 +1,44 @@
# CHANGELOG
## v2.45.13 (2025-12-17)
### Bug Fixes
- **scan queue**: Adjustments for changes to the pydantic model of the scan queue
([`01c6e09`](https://github.com/bec-project/bec_widgets/commit/01c6e092b9cd46ae056c43e8c6576f7a570cce80))
## v2.45.12 (2025-12-16)
### Bug Fixes
- **heatmap**: Flush image if config changes during scan
([`e0fd976`](https://github.com/bec-project/bec_widgets/commit/e0fd97616d370722e2ebf12d0f93862ac35cb20d))
- **heatmap**: Grid scan image correctly map to scan positions
([`6af8a5c`](https://github.com/bec-project/bec_widgets/commit/6af8a5cbfe0f97327b31039033d3e6946388347c))
- **heatmap**: More robust logic for fast and slow axis in grid scan
([`d876ca7`](https://github.com/bec-project/bec_widgets/commit/d876ca72bc50f967f0872eb777f2378a3db68ddf))
## v2.45.11 (2025-12-15)
### Bug Fixes
- **waveform**: Support for AsyncMultiSignal
([`cd11a6c`](https://github.com/bec-project/bec_widgets/commit/cd11a6cce33f3c0642984ae6b2d159c7441e22c6))
## v2.45.10 (2025-12-10)
### Bug Fixes
- **devices**: Minor fix to comply with new config helper in bec_lib
([`04f1ff4`](https://github.com/bec-project/bec_widgets/commit/04f1ff4fe7869215f010bf73f7271e063e21f2a2))
## v2.45.9 (2025-12-09)
### Bug Fixes

View File

@@ -268,6 +268,20 @@ class Heatmap(ImageBase):
if show_config_label is None:
show_config_label = self._image_config.show_config_label
def _device_key(device: HeatmapDeviceSignal | None) -> tuple[str | None, str | None]:
return (device.name if device else None, device.entry if device else None)
prev_cfg = getattr(self, "_image_config", None)
config_changed = False
if prev_cfg and prev_cfg.x_device and prev_cfg.y_device and prev_cfg.z_device:
config_changed = any(
(
_device_key(prev_cfg.x_device) != (x_name, x_entry),
_device_key(prev_cfg.y_device) != (y_name, y_entry),
_device_key(prev_cfg.z_device) != (z_name, z_entry),
)
)
self._image_config = HeatmapConfig(
parent_id=self.gui_id,
x_device=HeatmapDeviceSignal(name=x_name, entry=x_entry),
@@ -282,7 +296,10 @@ class Heatmap(ImageBase):
show_config_label=show_config_label,
)
self.color_map = color_map
self.reload = reload
self.reload = reload or config_changed
if config_changed:
self._grid_index = None
self.main_image.clear()
self.update_labels()
self._fetch_running_scan()
@@ -603,55 +620,51 @@ class Heatmap(ImageBase):
args = self.arg_bundle_to_dict(4, msg.request_inputs["arg_bundle"])
shape = (
args[self._image_config.x_device.entry][-1],
args[self._image_config.y_device.entry][-1],
)
x_entry = self._image_config.x_device.entry
y_entry = self._image_config.y_device.entry
shape = (args[x_entry][-1], args[y_entry][-1])
data = self.main_image.raw_data
if data is None or data.shape != shape:
data = np.empty(shape)
data.fill(np.nan)
def _get_grid_data(axis, snaked=True):
x_grid, y_grid = np.meshgrid(axis[0], axis[1])
if snaked:
y_grid.T[::2] = np.fliplr(y_grid.T[::2])
x_flat = x_grid.T.ravel()
y_flat = y_grid.T.ravel()
positions = np.vstack((x_flat, y_flat)).T
return positions
elif self.reload:
data.fill(np.nan)
snaked = msg.request_inputs["kwargs"].get("snaked", True)
# If the scan's fast axis is x, we need to swap the x and y axes
swap = bool(msg.request_inputs["arg_bundle"][4] == self._image_config.x_device.entry)
slow_entry, fast_entry = (
msg.request_inputs["arg_bundle"][0],
msg.request_inputs["arg_bundle"][4],
)
# calculate the QTransform to put (0,0) at the axis origin
scan_pos = np.asarray(msg.info["positions"])
x_min = min(scan_pos[:, 0])
x_max = max(scan_pos[:, 0])
y_min = min(scan_pos[:, 1])
y_max = max(scan_pos[:, 1])
scan_pos = np.asarray(msg.info["positions"], dtype=float)
relative = bool(msg.request_inputs["kwargs"].get("relative", False))
x_range = x_max - x_min
y_range = y_max - y_min
def _axis_column(entry: str) -> int:
return 0 if entry == slow_entry else 1
pixel_size_x = x_range / (shape[0] - 1)
pixel_size_y = y_range / (shape[1] - 1)
def _axis_levels(entry: str, npts: int) -> np.ndarray:
start, stop = args[entry][:2]
if relative:
origin = float(scan_pos[0, _axis_column(entry)] - start)
return origin + np.linspace(start, stop, npts)
return np.linspace(start, stop, npts)
x_levels = _axis_levels(x_entry, shape[0])
y_levels = _axis_levels(y_entry, shape[1])
pixel_size_x = (
float(x_levels[-1] - x_levels[0]) / max(shape[0] - 1, 1) if shape[0] > 1 else 1.0
)
pixel_size_y = (
float(y_levels[-1] - y_levels[0]) / max(shape[1] - 1, 1) if shape[1] > 1 else 1.0
)
transform = QTransform()
if swap:
transform.scale(pixel_size_y, pixel_size_x)
transform.translate(y_min / pixel_size_y - 0.5, x_min / pixel_size_x - 0.5)
else:
transform.scale(pixel_size_x, pixel_size_y)
transform.translate(x_min / pixel_size_x - 0.5, y_min / pixel_size_y - 0.5)
target_positions = _get_grid_data(
(np.arange(shape[int(swap)]), np.arange(shape[int(not swap)])), snaked=snaked
)
transform.scale(pixel_size_x, pixel_size_y)
transform.translate(x_levels[0] / pixel_size_x - 0.5, y_levels[0] / pixel_size_y - 0.5)
# Fill the data array with the z values
if self._grid_index is None or self.reload:
@@ -659,7 +672,16 @@ class Heatmap(ImageBase):
self.reload = False
for i in range(self._grid_index, len(z_data)):
data[target_positions[i, int(swap)], target_positions[i, int(not swap)]] = z_data[i]
slow_i, fast_i = divmod(i, args[fast_entry][-1])
if snaked and (slow_i % 2 == 1):
fast_i = args[fast_entry][-1] - 1 - fast_i
if x_entry == fast_entry:
x_i, y_i = fast_i, slow_i
else:
x_i, y_i = slow_i, fast_i
data[x_i, y_i] = z_data[i]
self._grid_index = len(z_data)
return data, transform

View File

@@ -1520,7 +1520,7 @@ class Waveform(PlotBase):
self.request_dap_update.emit()
def _check_async_signal_found(self, name: str, signal: str) -> bool:
def _check_async_signal_found(self, name: str, signal: str) -> tuple[bool, str]:
"""
Check if the async signal is found in the BEC device manager.
@@ -1529,13 +1529,16 @@ class Waveform(PlotBase):
signal(str): The entry of the async signal.
Returns:
bool: True if the async signal is found, False otherwise.
tuple[bool, str]: A tuple where the first element is True if the async signal is found (False otherwise),
and the second element is the signal name (either the original signal or the storage_name for AsyncMultiSignal).
"""
bec_async_signals = self.client.device_manager.get_bec_signals("AsyncSignal")
bec_async_signals = self.client.device_manager.get_bec_signals(
["AsyncSignal", "AsyncMultiSignal"]
)
for entry_name, _, entry_data in bec_async_signals:
if entry_name == name and entry_data.get("obj_name") == signal:
return True
return False
return True, entry_data.get("storage_name")
return False, signal
def _setup_async_curve(self, curve: Curve):
"""
@@ -1546,7 +1549,7 @@ class Waveform(PlotBase):
"""
name = curve.config.signal.name
signal = curve.config.signal.entry
async_signal_found = self._check_async_signal_found(name, signal)
async_signal_found, signal = self._check_async_signal_found(name, signal)
try:
curve.clear_data()

View File

@@ -6,6 +6,7 @@ import time
from typing import Literal
import numpy as np
from bec_lib import messages
from bec_lib.endpoints import MessageEndpoints
from bec_lib.logger import bec_logger
from qtpy.QtCore import QObject, QTimer, Signal
@@ -264,22 +265,28 @@ class ScanProgressBar(BECWidget, QWidget):
"""
if not "queue" in msg_content:
return
primary_queue_info = msg_content["queue"].get("primary", {}).get("info", [])
if "primary" not in msg_content["queue"]:
return
if (primary_queue := msg_content.get("queue").get("primary")) is None:
return
if not isinstance(primary_queue, messages.ScanQueueStatus):
return
primary_queue_info = primary_queue.info
if len(primary_queue_info) == 0:
return
scan_info = primary_queue_info[0]
if scan_info is None:
return
if scan_info.get("status").lower() == "running" and self.task is None:
if scan_info.status.lower() == "running" and self.task is None:
self.task = ProgressTask(parent=self)
self.progress_started.emit()
active_request_block = scan_info.get("active_request_block", {})
active_request_block = scan_info.active_request_block
if active_request_block is None:
return
self.scan_number = active_request_block.get("scan_number")
report_instructions = active_request_block.get("report_instructions", [])
self.scan_number = active_request_block.scan_number
report_instructions = active_request_block.report_instructions
if not report_instructions:
return

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
from bec_lib import messages
from bec_lib.endpoints import MessageEndpoints
from bec_qthemes import material_icon
from qtpy.QtCore import Property, Qt, Signal, Slot
@@ -145,7 +146,16 @@ class BECQueue(BECWidget, CompactPopupWidget):
_metadata (dict): The metadata.
"""
# only show the primary queue for now
queue_info = content.get("queue", {}).get("primary", {}).get("info", [])
queues = content.get("queue", {})
if not queues:
self.reset_content()
return
primary_queue: messages.ScanQueueStatus | None = queues.get("primary")
if not primary_queue:
self.reset_content()
return
queue_info = primary_queue.info
self.table.setRowCount(len(queue_info))
self.table.clearContents()
@@ -154,19 +164,19 @@ class BECQueue(BECWidget, CompactPopupWidget):
return
for index, item in enumerate(queue_info):
blocks = item.get("request_blocks", [])
blocks = item.request_blocks
scan_types = []
scan_numbers = []
scan_ids = []
status = item.get("status", "")
status = item.status
for request_block in blocks:
scan_type = request_block.get("content", {}).get("scan_type", "")
scan_type = request_block.msg.scan_type
if scan_type:
scan_types.append(scan_type)
scan_number = request_block.get("scan_number", "")
scan_number = request_block.scan_number
if scan_number:
scan_numbers.append(str(scan_number))
scan_id = request_block.get("scan_id", "")
scan_id = request_block.scan_id
if scan_id:
scan_ids.append(scan_id)
if scan_types:
@@ -178,7 +188,7 @@ class BECQueue(BECWidget, CompactPopupWidget):
self.set_row(index, scan_numbers, scan_types, status, scan_ids)
busy = (
False
if all(item.get("status") in ("STOPPED", "COMPLETED", "IDLE") for item in queue_info)
if all(item.status in ("STOPPED", "COMPLETED", "IDLE") for item in queue_info)
else True
)
self.set_global_state("warning" if busy else "default")

View File

@@ -55,7 +55,9 @@ class DeviceBrowser(BECWidget, QWidget):
) -> None:
super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
self.get_bec_shortcuts()
self._config_helper = ConfigHelper(self.client.connector, self.client._service_name)
self._config_helper = ConfigHelper(
self.client.connector, self.client._service_name, self.client.device_manager
)
self._q_threadpool = QThreadPool()
self.ui = None
self.init_ui()

View File

@@ -65,7 +65,7 @@ class DeviceConfigDialog(BECWidget, QDialog):
self._initial_config = {}
super().__init__(parent=parent, **kwargs)
self._config_helper = config_helper or ConfigHelper(
self.client.connector, self.client._service_name
self.client.connector, self.client._service_name, self.client.device_manager
)
self._device = device
self._action: Literal["update", "add"] = action

View File

@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "bec_widgets"
version = "2.45.9"
version = "2.45.13"
description = "BEC Widgets"
requires-python = ">=3.11"
classifiers = [

View File

@@ -134,7 +134,7 @@ def test_update_cycle(update_dialog, qtbot):
"deviceClass": "TestDevice",
"deviceConfig": {"param1": "val1"},
"readoutPriority": "monitored",
"description": None,
"description": "",
"readOnly": False,
"softwareTrigger": False,
"onFailure": "retry",

View File

@@ -4,6 +4,7 @@ import numpy as np
import pytest
from bec_lib import messages
from bec_lib.scan_history import ScanHistory
from qtpy.QtCore import QPointF
from bec_widgets.widgets.plots.heatmap.heatmap import Heatmap, HeatmapConfig, HeatmapDeviceSignal
@@ -125,12 +126,16 @@ def test_heatmap_get_image_data_unsupported_scan(heatmap_widget):
def test_heatmap_get_grid_scan_image(heatmap_widget):
x_levels = np.linspace(-5, 5, 10).tolist()
y_levels = np.linspace(-5, 5, 10).tolist()
scan_msg = messages.ScanStatusMessage(
scan_id="123",
status="open",
scan_name="grid_scan",
metadata={},
info={"positions": np.random.rand(100, 2).tolist()},
info={
"positions": _grid_positions(slow_levels=x_levels, fast_levels=y_levels, snaked=True)
},
request_inputs={"arg_bundle": ["samx", -5, 5, 10, "samy", -5, 5, 10], "kwargs": {}},
)
heatmap_widget._image_config = HeatmapConfig(
@@ -145,6 +150,111 @@ def test_heatmap_get_grid_scan_image(heatmap_widget):
assert sorted(np.asarray(img, dtype=int).flatten().tolist()) == list(range(100))
def _grid_positions(
*, slow_levels: list[float], fast_levels: list[float], snaked: bool, slow_is_col0: bool = True
) -> list[list[float]]:
positions: list[list[float]] = []
for slow_i, slow_val in enumerate(slow_levels):
row_fast = fast_levels if (not snaked or slow_i % 2 == 0) else list(reversed(fast_levels))
for fast_val in row_fast:
if slow_is_col0:
positions.append([slow_val, fast_val])
else:
positions.append([fast_val, slow_val])
return positions
def test_heatmap_grid_scan_direction_and_snaking_x_fast(heatmap_widget):
heatmap_widget._image_config = HeatmapConfig(
parent_id="parent_id",
x_device=HeatmapDeviceSignal(name="samx", entry="samx"),
y_device=HeatmapDeviceSignal(name="samy", entry="samy"),
z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"),
color_map="viridis",
)
# x decreases (relative), y increases (relative), x is fast axis
x0 = 10.0
y0 = -3.0
x_levels = (x0 + np.linspace(1.0, -1.0, 3)).tolist()
y_levels = (y0 + np.linspace(-2.0, 2.0, 2)).tolist()
snaked = True
scan_msg = messages.ScanStatusMessage(
scan_id="123",
status="open",
scan_name="grid_scan",
metadata={},
info={
"positions": _grid_positions(slow_levels=y_levels, fast_levels=x_levels, snaked=snaked)
},
request_inputs={
"arg_bundle": ["samy", -2.0, 2.0, 2, "samx", 1.0, -1.0, 3],
"kwargs": {"snaked": snaked, "relative": True},
},
)
img, transform = heatmap_widget.get_grid_scan_image(list(range(6)), msg=scan_msg)
assert img.shape == (3, 2)
assert img[0, 0] == 0 # first point: (x0,y0) in scan order
assert img[2, 1] == 3 # second row first point due to snaking
assert img[0, 1] == 5 # last point in second row
p0 = transform.map(QPointF(0.5, 0.5))
p1 = transform.map(QPointF(2.5, 1.5))
assert p0.x() == pytest.approx(x_levels[0])
assert p0.y() == pytest.approx(y_levels[0])
assert p1.x() == pytest.approx(x_levels[-1])
assert p1.y() == pytest.approx(y_levels[-1])
def test_heatmap_grid_scan_direction_and_snaking_y_fast(heatmap_widget):
heatmap_widget._image_config = HeatmapConfig(
parent_id="parent_id",
x_device=HeatmapDeviceSignal(name="samx", entry="samx"),
y_device=HeatmapDeviceSignal(name="samy", entry="samy"),
z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"),
color_map="viridis",
)
# x decreases (relative), y increases (relative), y is fast axis
x0 = 1.5
y0 = 22.0
x_levels = (x0 + np.linspace(1.0, -1.0, 3)).tolist()
y_levels = (y0 + np.linspace(-2.0, 2.0, 2)).tolist()
snaked = True
scan_msg = messages.ScanStatusMessage(
scan_id="123",
status="open",
scan_name="grid_scan",
metadata={},
info={
"positions": _grid_positions(slow_levels=x_levels, fast_levels=y_levels, snaked=snaked)
},
request_inputs={
"arg_bundle": ["samx", 1.0, -1.0, 3, "samy", -2.0, 2.0, 2],
"kwargs": {"snaked": snaked, "relative": True},
},
)
img, transform = heatmap_widget.get_grid_scan_image(list(range(6)), msg=scan_msg)
assert img.shape == (3, 2)
assert img[0, 0] == 0
# For y-fast scans, snaking reverses the y index on every odd x row.
assert img[1, 1] == 2
assert img[1, 0] == 3
p0 = transform.map(QPointF(0.5, 0.5))
p1 = transform.map(QPointF(2.5, 1.5))
assert p0.x() == pytest.approx(x_levels[0])
assert p0.y() == pytest.approx(y_levels[0])
assert p1.x() == pytest.approx(x_levels[-1])
assert p1.y() == pytest.approx(y_levels[-1])
def test_heatmap_get_step_scan_image(heatmap_widget):
scan_msg = messages.ScanStatusMessage(
@@ -193,12 +303,16 @@ def test_heatmap_update_plot(heatmap_widget):
color_map="viridis",
)
heatmap_widget.scan_item = create_dummy_scan_item()
x_levels = np.linspace(-5, 5, 10).tolist()
y_levels = np.linspace(-5, 5, 10).tolist()
heatmap_widget.scan_item.status_message = messages.ScanStatusMessage(
scan_id="123",
status="open",
scan_name="grid_scan",
metadata={},
info={"positions": np.random.rand(100, 2).tolist()},
info={
"positions": _grid_positions(slow_levels=x_levels, fast_levels=y_levels, snaked=True)
},
request_inputs={"arg_bundle": ["samx", -5, 5, 10, "samy", -5, 5, 10], "kwargs": {}},
)
with mock.patch.object(heatmap_widget.main_image, "setImage") as mock_set_image:

View File

@@ -25,6 +25,30 @@ def scan_progressbar(qtbot, mocked_client):
yield widget
@pytest.fixture
def scan_message():
return messages.ScanQueueMessage(
metadata={
"file_suffix": None,
"file_directory": None,
"user_metadata": {"sample_name": ""},
"RID": "94949c6e-d5f2-4f01-837e-a5d36257dd5d",
},
scan_type="line_scan",
parameter={
"args": {"samx": [-10.0, 10.0]},
"kwargs": {
"steps": 20,
"relative": False,
"exp_time": 0.1,
"burst_at_each_point": 1,
"system_config": {"file_suffix": None, "file_directory": None},
},
},
queue="primary",
)
def test_progress_task_basic():
"""percentage, remaining, and formatted time helpers behave as expected."""
task = ProgressTask(parent=None, value=50, max_value=100, done=False)
@@ -167,7 +191,9 @@ def test_progressbar_queue_update(scan_progressbar):
"""
Test that an empty queue update does not change the progress source.
"""
msg = messages.ScanQueueStatusMessage(queue={"primary": {"info": [], "status": "RUNNING"}})
msg = messages.ScanQueueStatusMessage(
queue={"primary": messages.ScanQueueStatus(info=[], status="RUNNING")}
)
with mock.patch.object(scan_progressbar, "set_progress_source") as mock_set_source:
scan_progressbar.on_queue_update(
msg.content, msg.metadata, _override_slot_params={"verify_sender": False}
@@ -175,50 +201,37 @@ def test_progressbar_queue_update(scan_progressbar):
mock_set_source.assert_not_called()
def test_progressbar_queue_update_with_scan(scan_progressbar):
def test_progressbar_queue_update_with_scan(scan_progressbar, scan_message):
"""
Test that a queue update with a scan changes the progress source to SCAN_PROGRESS.
"""
request_block = messages.RequestBlock(
msg=scan_message,
RID="some-rid",
scan_motors=["samx"],
readout_priority={"monitored": ["samx"]},
is_scan=True,
scan_number=1,
scan_id="e3f50794-852c-4bb1-965e-41c585ab0aa9",
report_instructions=[{"scan_progress": 20}],
)
msg = messages.ScanQueueStatusMessage(
metadata={},
queue={
"primary": {
"info": [
{
"queue_id": "40831e2c-fbd1-4432-8072-ad168a7ad964",
"scan_id": ["e3f50794-852c-4bb1-965e-41c585ab0aa9"],
"status": "RUNNING",
"active_request_block": {
"msg": messages.ScanQueueMessage(
metadata={
"file_suffix": None,
"file_directory": None,
"user_metadata": {"sample_name": ""},
"RID": "94949c6e-d5f2-4f01-837e-a5d36257dd5d",
},
scan_type="line_scan",
parameter={
"args": {"samx": [-10.0, 10.0]},
"kwargs": {
"steps": 20,
"relative": False,
"exp_time": 0.1,
"burst_at_each_point": 1,
"system_config": {
"file_suffix": None,
"file_directory": None,
},
},
},
queue="primary",
),
"scan_number": 1,
"report_instructions": [{"scan_progress": 20}],
},
}
"primary": messages.ScanQueueStatus(
info=[
messages.QueueInfoEntry(
queue_id="40831e2c-fbd1-4432-8072-ad168a7ad964",
scan_id=["e3f50794-852c-4bb1-965e-41c585ab0aa9"],
status="RUNNING",
active_request_block=request_block,
is_scan=[True],
request_blocks=[request_block],
scan_number=[1],
)
],
"status": "RUNNING",
}
status="RUNNING",
)
},
)
@@ -229,50 +242,37 @@ def test_progressbar_queue_update_with_scan(scan_progressbar):
mock_set_source.assert_called_once_with(ProgressSource.SCAN_PROGRESS)
def test_progressbar_queue_update_with_device(scan_progressbar):
def test_progressbar_queue_update_with_device(scan_progressbar, scan_message):
"""
Test that a queue update with a device changes the progress source to DEVICE_PROGRESS.
"""
request_block = messages.RequestBlock(
msg=scan_message,
RID="some-rid",
scan_motors=["samx"],
readout_priority={"monitored": ["samx"]},
is_scan=True,
scan_number=1,
scan_id="e3f50794-852c-4bb1-965e-41c585ab0aa9",
report_instructions=[{"device_progress": ["samx"]}],
)
msg = messages.ScanQueueStatusMessage(
metadata={},
queue={
"primary": {
"info": [
{
"queue_id": "40831e2c-fbd1-4432-8072-ad168a7ad964",
"scan_id": ["e3f50794-852c-4bb1-965e-41c585ab0aa9"],
"status": "RUNNING",
"active_request_block": {
"msg": messages.ScanQueueMessage(
metadata={
"file_suffix": None,
"file_directory": None,
"user_metadata": {"sample_name": ""},
"RID": "94949c6e-d5f2-4f01-837e-a5d36257dd5d",
},
scan_type="line_scan",
parameter={
"args": {"samx": [-10.0, 10.0]},
"kwargs": {
"steps": 20,
"relative": False,
"exp_time": 0.1,
"burst_at_each_point": 1,
"system_config": {
"file_suffix": None,
"file_directory": None,
},
},
},
queue="primary",
),
"scan_number": 1,
"report_instructions": [{"device_progress": ["samx"]}],
},
}
"primary": messages.ScanQueueStatus(
info=[
messages.QueueInfoEntry(
queue_id="40831e2c-fbd1-4432-8072-ad168a7ad964",
scan_id=["e3f50794-852c-4bb1-965e-41c585ab0aa9"],
status="RUNNING",
active_request_block=request_block,
is_scan=[True],
request_blocks=[request_block],
scan_number=[1],
)
],
"status": "RUNNING",
}
status="RUNNING",
)
},
)
@@ -283,49 +283,36 @@ def test_progressbar_queue_update_with_device(scan_progressbar):
mock_set_source.assert_called_once_with(ProgressSource.DEVICE_PROGRESS, device="samx")
def test_progressbar_queue_update_with_no_scan_or_device(scan_progressbar):
def test_progressbar_queue_update_with_no_scan_or_device(scan_progressbar, scan_message):
"""
Test that a queue update with neither scan nor device does not change the progress source.
"""
request_block = messages.RequestBlock(
msg=scan_message,
RID="some-rid",
scan_motors=["samx"],
readout_priority={"monitored": ["samx"]},
is_scan=True,
scan_number=1,
scan_id="e3f50794-852c-4bb1-965e-41c585ab0aa9",
)
msg = messages.ScanQueueStatusMessage(
metadata={},
queue={
"primary": {
"info": [
{
"queue_id": "40831e2c-fbd1-4432-8072-ad168a7ad964",
"scan_id": ["e3f50794-852c-4bb1-965e-41c585ab0aa9"],
"status": "RUNNING",
"active_request_block": {
"msg": messages.ScanQueueMessage(
metadata={
"file_suffix": None,
"file_directory": None,
"user_metadata": {"sample_name": ""},
"RID": "94949c6e-d5f2-4f01-837e-a5d36257dd5d",
},
scan_type="line_scan",
parameter={
"args": {"samx": [-10.0, 10.0]},
"kwargs": {
"steps": 20,
"relative": False,
"exp_time": 0.1,
"burst_at_each_point": 1,
"system_config": {
"file_suffix": None,
"file_directory": None,
},
},
},
queue="primary",
),
"scan_number": 1,
},
}
"primary": messages.ScanQueueStatus(
info=[
messages.QueueInfoEntry(
queue_id="40831e2c-fbd1-4432-8072-ad168a7ad964",
scan_id=["e3f50794-852c-4bb1-965e-41c585ab0aa9"],
status="RUNNING",
active_request_block=request_block,
is_scan=[True],
request_blocks=[request_block],
scan_number=[1],
)
],
"status": "RUNNING",
}
status="RUNNING",
)
},
)