Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def queue_elements(bec_client_mock):
client = bec_client_mock
request_msg = messages.ScanQueueMessage(
scan_type="grid_scan",
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
parameter={"args": {"samx": [-5, 5, 3]}, "kwargs": {}},
queue="primary",
metadata={"RID": "something"},
)
Expand Down Expand Up @@ -52,7 +52,7 @@ def queue_elements(bec_client_mock):
def sample_request_msg():
return messages.ScanQueueMessage(
scan_type="grid_scan",
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
parameter={"args": {"samx": [-5, 5, 3]}, "kwargs": {}},
queue="primary",
metadata={"RID": "something"},
)
Expand Down Expand Up @@ -232,7 +232,7 @@ def test_available_req_blocks_multiple_blocks(bec_client_mock):

request_msg = messages.ScanQueueMessage(
scan_type="grid_scan",
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
parameter={"args": {"samx": [-5, 5, 3]}, "kwargs": {}},
queue="primary",
metadata={"RID": "test_rid"},
)
Expand Down
20 changes: 11 additions & 9 deletions bec_ipython_client/tests/client_tests/test_live_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def client_with_grid_scan(bec_client_mock):
client = bec_client_mock
request_msg = messages.ScanQueueMessage(
scan_type="grid_scan",
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
parameter={"args": {"samx": [-5, 5, 3]}, "kwargs": {}},
queue="primary",
metadata={"RID": "something"},
)
Expand Down Expand Up @@ -88,7 +88,7 @@ def test_sort_devices(self):
(
messages.ScanQueueMessage(
scan_type="grid_scan",
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
parameter={"args": {"samx": [-5, 5, 3]}, "kwargs": {}},
queue="primary",
metadata={"RID": "something"},
),
Expand Down Expand Up @@ -134,7 +134,7 @@ def test_wait_for_request_acceptance(self, client_with_grid_scan):
def test_run_update(self, bec_client_mock, scan_item):
request_msg = messages.ScanQueueMessage(
scan_type="grid_scan",
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
parameter={"args": {"samx": [-5, 5, 3]}, "kwargs": {}},
queue="primary",
metadata={"RID": "something"},
)
Expand All @@ -161,7 +161,7 @@ def test_run_update(self, bec_client_mock, scan_item):
def test_run_update_without_monitored_devices(self, bec_client_mock, scan_item):
request_msg = messages.ScanQueueMessage(
scan_type="grid_scan",
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
parameter={"args": {"samx": [-5, 5, 3]}, "kwargs": {}},
queue="primary",
metadata={"RID": "something"},
)
Expand Down Expand Up @@ -303,8 +303,10 @@ def test_print_table_data_hinted_value_with_precision(
@pytest.mark.parametrize(
"value,expected",
[
(np.int32(1), "1.00"),
(np.float64(1.00000), "1.00"),
# Commented out cases are not supported in unstructured serialized data, because msgpack doesn't distinguish
# lists, tuples, or sets. To support this, ScanMessage must be refactored to support the type information directly
# (np.int32(1), "1.00"),
# (np.float64(1.00000), "1.00"),
(0, "0.00"),
(1, "1.00"),
(0.000, "0.00"),
Expand All @@ -314,10 +316,10 @@ def test_print_table_data_hinted_value_with_precision(
("False", "False"),
("0", "0"),
("1", "1"),
((0, 1), "(0, 1)"),
# ((0, 1), "(0, 1)"),
({"value": 0}, "{'value': 0}"),
(np.array([0, 1]), "[0 1]"),
({1, 2}, "{1, 2}"),
# (np.array([0, 1]), "[0 1]"),
# ({1, 2}, "{1, 2}"),
],
)
def test_print_table_data_variants(self, client_with_grid_scan, value, expected):
Expand Down
2 changes: 1 addition & 1 deletion bec_ipython_client/tests/end-2-end/test_scans_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ def test_scan_repeat_decorator(bec_ipython_client_fixture):
"update_frequency": 400,
},
"readoutPriority": "baseline",
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"enabled": True,
"readOnly": False,
}
Expand Down
26 changes: 13 additions & 13 deletions bec_ipython_client/tests/end-2-end/test_scans_lib_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def test_dap_fit(bec_client_lib):
"hexapod": {
"deviceClass": "ophyd_devices.SynDeviceOPAAS",
"deviceConfig": {},
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"readoutPriority": "baseline",
"enabled": True,
"readOnly": False,
Expand All @@ -230,7 +230,7 @@ def test_dap_fit(bec_client_lib):
"tolerance": 0.01,
"update_frequency": 400,
},
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"enabled": True,
"readOnly": False,
},
Expand All @@ -244,7 +244,7 @@ def test_dap_fit(bec_client_lib):
"hexapod": {
"deviceClass": "ophyd_devices.SynDeviceOPAAS",
"deviceConfig": {},
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"readoutPriority": "baseline",
"enabled": True,
"readOnly": False,
Expand All @@ -258,7 +258,7 @@ def test_dap_fit(bec_client_lib):
"update_frequency": 400,
},
"readoutPriority": "baseline",
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"enabled": True,
"readOnly": False,
},
Expand All @@ -272,7 +272,7 @@ def test_dap_fit(bec_client_lib):
"hexapod": {
"deviceClass": "ophyd_devices.SynDeviceOPAAS",
"deviceConfig": {},
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"readoutPriority": "baseline",
"enabled": True,
"readOnly": False,
Expand All @@ -281,7 +281,7 @@ def test_dap_fit(bec_client_lib):
"deviceClass": "ophyd_devices.utils.bec_utils.DeviceClassConnectionError",
"deviceConfig": {},
"readoutPriority": "baseline",
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"enabled": True,
"readOnly": False,
},
Expand All @@ -295,7 +295,7 @@ def test_dap_fit(bec_client_lib):
"hexapod": {
"deviceClass": "SynDeviceOPAAS",
"deviceConfig": {},
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"readoutPriority": "baseline",
"enabled": True,
"readOnly": False,
Expand All @@ -304,7 +304,7 @@ def test_dap_fit(bec_client_lib):
"deviceClass": "ophyd_devices.utils.bec_utils.DeviceClassInitError",
"deviceConfig": {},
"readoutPriority": "baseline",
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"enabled": True,
"readOnly": False,
},
Expand All @@ -318,7 +318,7 @@ def test_dap_fit(bec_client_lib):
"hexapod": {
"deviceClass": "SynDeviceOPAAS",
"deviceConfig": {},
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"readoutPriority": "baseline",
"enabled": True,
"readOnly": False,
Expand All @@ -327,7 +327,7 @@ def test_dap_fit(bec_client_lib):
"deviceClass": "ophyd_devices.WrongDeviceClass",
"deviceConfig": {},
"readoutPriority": "baseline",
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"enabled": True,
"readOnly": False,
},
Expand Down Expand Up @@ -383,7 +383,7 @@ def test_config_reload_with_describe_failure(bec_test_config_file_path, bec_clie
"hexapod": {
"deviceClass": "ophyd_devices.sim.sim_test_devices.SimPositionerWithDescribeFailure",
"deviceConfig": {},
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"readoutPriority": "baseline",
"enabled": True,
"readOnly": False,
Expand All @@ -397,7 +397,7 @@ def test_config_reload_with_describe_failure(bec_test_config_file_path, bec_clie
"update_frequency": 400,
},
"readoutPriority": "baseline",
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"enabled": True,
"readOnly": False,
},
Expand Down Expand Up @@ -445,7 +445,7 @@ def test_config_add_remove_device(bec_client_lib):
"update_frequency": 400,
},
"readoutPriority": "baseline",
"deviceTags": {"user motors"},
"deviceTags": ["user motors"],
"enabled": True,
"readOnly": False,
}
Expand Down
33 changes: 33 additions & 0 deletions bec_lib/bec_lib/bec_serializable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import numpy as np
from pydantic import BaseModel, ConfigDict, computed_field


class BecCodecInfo(BaseModel):
type_name: str


class BECSerializable(BaseModel):
"""A base class for serializable BEC objects, especially BEC messages.
Fields in subclasses which use non-primitive types must be in structured,
type-hinted objects, and their encoders and JSON schema should be defined in
this class."""

model_config = ConfigDict(
json_schema_serialization_defaults_required=True,
arbitrary_types_allowed=True,
extra="forbid",
)

@computed_field()
@property
def bec_codec(self) -> BecCodecInfo:
return BecCodecInfo(type_name=self.__class__.__name__)

def __eq__(self, other):
if type(other) is not type(self):
return False
try:
np.testing.assert_equal(self.model_dump(), other.model_dump())
return True
except AssertionError:
return False
6 changes: 3 additions & 3 deletions bec_lib/bec_lib/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def _prepare_rpc_msg(
client: BECClient = self.root.parent.parent
msg = messages.ScanQueueMessage(
scan_type="device_rpc",
parameter=params,
parameter=messages.sanitize_one_way_encodable(params),
queue=client.queue.get_default_scan_queue(), # type: ignore
metadata={"RID": request_id, "response": True},
)
Expand Down Expand Up @@ -1115,8 +1115,8 @@ def limits(self):
if not limit_msg:
return [0, 0]
limits = [
limit_msg.content["signals"].get("low", {}).get("value", 0),
limit_msg.content["signals"].get("high", {}).get("value", 0),
limit_msg.signals.get("low", {}).get("value", 0),
limit_msg.signals.get("high", {}).get("value", 0),
]
return limits

Expand Down
11 changes: 10 additions & 1 deletion bec_lib/bec_lib/devicemanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,9 +667,18 @@ def _get_redis_device_config(self) -> list:

def _add_multiple_devices_with_log(self, devices: Iterable[tuple[dict, DeviceInfoMessage]]):
logs = (self._add_device(*conf_msg) for conf_msg in devices if conf_msg is not None)
logger.info(f"Adding new devices:\n" + ", ".join(f"{name}: {t}" for name, t in logs)) # type: ignore # filtered
if set(logs) == {None}:
logger.warning("No devices added!")
return
logger.info(
f"Adding new devices:\n"
+ ", ".join(f"{log[0]}: {log[1]}" for log in logs if log is not None)
)

def _add_device(self, dev: dict, msg: DeviceInfoMessage) -> tuple[str, str] | None:
if msg is None:
logger.error(f"No device info in Redis for: {dev}")
return None
name = msg.content["device"]
info = msg.content["info"]

Expand Down
Loading
Loading