Skip to content
Merged
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
12 changes: 7 additions & 5 deletions src/fastcs/attributes/attr_r.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ async def update(self, value: Any) -> None:
ValueError: If the value fails to be validated to DType_T

"""
self.log_event(
"Attribute set", value=value, value_type=type(value), attribute=self
)
self.log_event("Attribute set", value=repr(value), attribute=self)

_previous_value = self._value
self._value = self._datatype.validate(value)

self.log_event("Value validated", value=repr(self._value), attribute=self)

self._on_update_events -= {
e for e in self._on_update_events if e.set(self._value)
}
Expand All @@ -94,7 +94,9 @@ async def update(self, value: Any) -> None:
await asyncio.gather(*[cb(self._value) for cb in callbacks_to_call])
except Exception as e:
logger.opt(exception=e).error(
"On update callbacks failed", attribute=self, value=value
"On update callbacks failed",
attribute=self,
value=repr(self._value),
)
raise

Expand Down Expand Up @@ -201,5 +203,5 @@ def predicate(v: DType_T) -> bool:
) from None

self.log_event(
"Value equals target value", target_valuevalue=target_value, attribute=self
"Value equals target value", target_value=target_value, attribute=self
)
2 changes: 1 addition & 1 deletion src/fastcs/attributes/attr_rw.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ async def update(self, value: DType_T):
await super().update(value)

if not self._setpoint_initialised:
await self._call_sync_setpoint_callbacks(value)
await self._call_sync_setpoint_callbacks(self._value)
self._setpoint_initialised = True
8 changes: 5 additions & 3 deletions src/fastcs/transports/epics/ca/ioc.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ def _create_and_link_read_pv(
pv = f"{pv_prefix}:{pv_name}"

async def async_record_set(value: DType_T):
tracer.log_event("PV set from attribute", topic=attribute, pv=pv, value=value)
tracer.log_event(
"PV set from attribute", topic=attribute, pv=pv, value=repr(value)
)

record.set(cast_to_epics_type(attribute.datatype, value))

Expand Down Expand Up @@ -217,13 +219,13 @@ def _create_and_link_write_pv(
pv = f"{pv_prefix}:{pv_name}"

async def on_update(value):
logger.info("PV put: {pv} = {value}", pv=pv, value=value)
logger.info("PV put: {pv} = {value}", pv=pv, value=repr(value))

await attribute.put(cast_from_epics_type(attribute.datatype, value))

async def set_setpoint_without_process(value: DType_T):
tracer.log_event(
"PV setpoint set from attribute", topic=attribute, pv=pv, value=value
"PV setpoint set from attribute", topic=attribute, pv=pv, value=repr(value)
)

record.set(cast_to_epics_type(attribute.datatype, value), process=False)
Expand Down
27 changes: 27 additions & 0 deletions tests/test_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,33 @@ def test_attr_r():
assert attr.get() == ""


@pytest.mark.asyncio
async def test_attr_update(mocker: MockerFixture):
attr = AttrRW(Int())

await attr.update(42)
assert attr.get() == 42

await attr.update("100") # type: ignore
assert attr.get() == 100

with pytest.raises(ValueError, match="Failed to cast"):
await attr.update("not_an_int") # type: ignore

attr = AttrRW(Int())
sync_setpoint_mock = mocker.AsyncMock()
attr.add_sync_setpoint_callback(sync_setpoint_mock)

await attr.update("200") # type: ignore
assert attr.get() == 200
sync_setpoint_mock.assert_called_once_with(200)

sync_setpoint_mock.reset_mock()
await attr.update(20)
assert attr.get() == 20
sync_setpoint_mock.assert_not_called()


@pytest.mark.asyncio
async def test_wait_for_predicate(mocker: MockerFixture):
attr = AttrR(Int(), initial_value=0)
Expand Down