From 8e60d4f053d4b7b20d9639ef8f9d40260cc114f8 Mon Sep 17 00:00:00 2001 From: James Souter Date: Mon, 11 Aug 2025 08:28:42 +0000 Subject: [PATCH 1/2] do not propagate DRVL and DRVH to in type records in CA transport --- src/fastcs/transport/epics/ca/util.py | 5 +++++ tests/transport/epics/ca/test_softioc.py | 22 ++++++++++++---------- tests/transport/epics/ca/test_util.py | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/fastcs/transport/epics/ca/util.py b/src/fastcs/transport/epics/ca/util.py index 271b3d939..9f009b34c 100644 --- a/src/fastcs/transport/epics/ca/util.py +++ b/src/fastcs/transport/epics/ca/util.py @@ -62,6 +62,11 @@ def record_metadata_from_datatype( if field in DATATYPE_FIELD_TO_RECORD_FIELD } + if not out_record: + # in type records don't have DRVL/DRVH fields + arguments.pop("DRVL", None) + arguments.pop("DRVH", None) + match datatype: case Waveform(): if len(datatype.shape) != 1: diff --git a/tests/transport/epics/ca/test_softioc.py b/tests/transport/epics/ca/test_softioc.py index d240c6c70..7ed4dfbed 100644 --- a/tests/transport/epics/ca/test_softioc.py +++ b/tests/transport/epics/ca/test_softioc.py @@ -181,7 +181,7 @@ def test_make_output_record( pv = "PV" _make_record(pv, attribute, on_update=update, out_record=True) - kwargs.update(record_metadata_from_datatype(attribute.datatype)) + kwargs.update(record_metadata_from_datatype(attribute.datatype, out_record=True)) kwargs.update(record_metadata_from_attribute(attribute)) kwargs.update({"always_update": True, "on_update": update}) @@ -266,7 +266,8 @@ def test_ioc(mocker: MockerFixture, epics_controller_api: ControllerAPI): epics_controller_api.attributes["read_write_float"] ), **record_metadata_from_datatype( - epics_controller_api.attributes["read_write_float"].datatype + epics_controller_api.attributes["read_write_float"].datatype, + out_record=True, ), ) builder.longIn.assert_any_call( @@ -286,7 +287,7 @@ def test_ioc(mocker: MockerFixture, epics_controller_api: ControllerAPI): epics_controller_api.attributes["read_write_int"] ), **record_metadata_from_datatype( - epics_controller_api.attributes["read_write_int"].datatype + epics_controller_api.attributes["read_write_int"].datatype, out_record=True ), ) builder.mbbIn.assert_called_once_with( @@ -302,7 +303,7 @@ def test_ioc(mocker: MockerFixture, epics_controller_api: ControllerAPI): on_update=mocker.ANY, **record_metadata_from_attribute(epics_controller_api.attributes["enum"]), **record_metadata_from_datatype( - epics_controller_api.attributes["enum"].datatype + epics_controller_api.attributes["enum"].datatype, out_record=True ), ) builder.boolOut.assert_called_once_with( @@ -311,7 +312,7 @@ def test_ioc(mocker: MockerFixture, epics_controller_api: ControllerAPI): on_update=mocker.ANY, **record_metadata_from_attribute(epics_controller_api.attributes["write_bool"]), **record_metadata_from_datatype( - epics_controller_api.attributes["write_bool"].datatype + epics_controller_api.attributes["write_bool"].datatype, out_record=True ), ) ioc_builder.Action.assert_any_call( @@ -452,7 +453,8 @@ def test_long_pv_names_discarded(mocker: MockerFixture): always_update=True, on_update=mocker.ANY, **record_metadata_from_datatype( - long_name_controller_api.attributes["attr_rw_short_name"].datatype + long_name_controller_api.attributes["attr_rw_short_name"].datatype, + out_record=True, ), **record_metadata_from_attribute( long_name_controller_api.attributes["attr_rw_short_name"] @@ -528,9 +530,9 @@ def test_update_datatype(mocker: MockerFixture): **record_metadata_from_datatype(attr_r.datatype), ) record_r.set_field.assert_not_called() - attr_r.update_datatype(Int(units="m", min=-3)) + attr_r.update_datatype(Int(units="m", min_alarm=-3)) record_r.set_field.assert_any_call("EGU", "m") - record_r.set_field.assert_any_call("DRVL", -3) + record_r.set_field.assert_any_call("LOPR", -3) with pytest.raises( ValueError, @@ -547,9 +549,9 @@ def test_update_datatype(mocker: MockerFixture): **record_metadata_from_datatype(attr_w.datatype), ) record_w.set_field.assert_not_called() - attr_w.update_datatype(Int(units="m", min=-3)) + attr_w.update_datatype(Int(units="m", min_alarm=-3)) record_w.set_field.assert_any_call("EGU", "m") - record_w.set_field.assert_any_call("DRVL", -3) + record_w.set_field.assert_any_call("LOPR", -3) with pytest.raises( ValueError, diff --git a/tests/transport/epics/ca/test_util.py b/tests/transport/epics/ca/test_util.py index e26e4cf45..14cd56065 100644 --- a/tests/transport/epics/ca/test_util.py +++ b/tests/transport/epics/ca/test_util.py @@ -9,6 +9,7 @@ builder_callable_from_attribute, cast_from_epics_type, cast_to_epics_type, + record_metadata_from_datatype, ) @@ -148,3 +149,18 @@ def test_builder_callable_enum_types(datatype, in_record, out_record): attr = AttrRW(datatype) assert builder_callable_from_attribute(attr, False) == out_record assert builder_callable_from_attribute(attr, True) == in_record + + +def test_drive_metadata_from_datatype(): + dtype = Float(units="mm", min=-10.0, max=10.0, min_alarm=-5, max_alarm=5, prec=3) + out_arguments = record_metadata_from_datatype(dtype, True) + assert out_arguments == { + "DRVH": 10.0, + "DRVL": -10.0, + "EGU": "mm", + "HOPR": 5, + "LOPR": -5, + "PREC": 3, + } + in_arguments = record_metadata_from_datatype(dtype, False) + assert in_arguments == {"EGU": "mm", "HOPR": 5, "LOPR": -5, "PREC": 3} From c6d03f4398897dd009cb8fd648d0b60c95df345d Mon Sep 17 00:00:00 2001 From: James Souter Date: Wed, 13 Aug 2025 12:41:34 +0000 Subject: [PATCH 2/2] fix out_record arg not being passed when updating datatype in ca transport --- src/fastcs/transport/epics/ca/ioc.py | 2 +- tests/transport/epics/ca/test_softioc.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/fastcs/transport/epics/ca/ioc.py b/src/fastcs/transport/epics/ca/ioc.py index c0cae76d2..9653328e0 100644 --- a/src/fastcs/transport/epics/ca/ioc.py +++ b/src/fastcs/transport/epics/ca/ioc.py @@ -187,7 +187,7 @@ def _make_record( ) def datatype_updater(datatype: DataType): - for name, value in record_metadata_from_datatype(datatype).items(): + for name, value in record_metadata_from_datatype(datatype, out_record).items(): record.set_field(name, value) attribute.add_update_datatype_callback(datatype_updater) diff --git a/tests/transport/epics/ca/test_softioc.py b/tests/transport/epics/ca/test_softioc.py index 7ed4dfbed..64805bffd 100644 --- a/tests/transport/epics/ca/test_softioc.py +++ b/tests/transport/epics/ca/test_softioc.py @@ -541,7 +541,7 @@ def test_update_datatype(mocker: MockerFixture): attr_r.update_datatype(String()) # type: ignore attr_w = AttrW(Int()) - record_w = _make_record(pv_name, attr_w, on_update=mocker.ANY) + record_w = _make_record(pv_name, attr_w, on_update=mocker.ANY, out_record=True) builder.longIn.assert_called_once_with( pv_name, @@ -549,9 +549,10 @@ def test_update_datatype(mocker: MockerFixture): **record_metadata_from_datatype(attr_w.datatype), ) record_w.set_field.assert_not_called() - attr_w.update_datatype(Int(units="m", min_alarm=-3)) + attr_w.update_datatype(Int(units="m", min_alarm=-1, min=-3)) record_w.set_field.assert_any_call("EGU", "m") - record_w.set_field.assert_any_call("LOPR", -3) + record_w.set_field.assert_any_call("LOPR", -1) + record_w.set_field.assert_any_call("DRVL", -3) with pytest.raises( ValueError,