diff --git a/src/fastcs/attributes.py b/src/fastcs/attributes.py index ab0494e89..160360db4 100644 --- a/src/fastcs/attributes.py +++ b/src/fastcs/attributes.py @@ -187,11 +187,7 @@ def __init__( ) self._process_callbacks: list[AttrCallback[T]] | None = None self._write_display_callbacks: list[AttrCallback[T]] | None = None - - if handler is not None: - self._setter = handler - else: - self._setter = SimpleAttrHandler() + self._setter = handler async def process(self, value: T) -> None: await self.process_without_display_update(value) @@ -221,7 +217,7 @@ def add_write_display_callback(self, callback: AttrCallback[T]) -> None: self._write_display_callbacks.append(callback) @property - def sender(self) -> AttrHandlerW: + def sender(self) -> AttrHandlerW | None: return self._setter @@ -241,7 +237,7 @@ def __init__( datatype, # type: ignore access_mode, group=group, - handler=handler, + handler=handler if handler else SimpleAttrHandler(), initial_value=initial_value, description=description, ) diff --git a/tests/example_p4p_ioc.py b/tests/example_p4p_ioc.py index 5fff09915..d7ce94745 100644 --- a/tests/example_p4p_ioc.py +++ b/tests/example_p4p_ioc.py @@ -3,7 +3,7 @@ import numpy as np -from fastcs.attributes import AttrR, AttrRW, AttrW +from fastcs.attributes import AttrHandlerW, AttrR, AttrRW, AttrW from fastcs.controller import Controller, SubController from fastcs.datatypes import Bool, Enum, Float, Int, Table, Waveform from fastcs.launch import FastCS @@ -14,6 +14,11 @@ from fastcs.wrappers import command, scan +class SimpleAttributeSetter(AttrHandlerW): + async def put(self, attr, value): + await attr.update_display_without_process(value) + + class FEnum(enum.Enum): A = 0 B = 1 @@ -25,7 +30,7 @@ class FEnum(enum.Enum): class ParentController(Controller): description = "some controller" a: AttrRW = AttrRW(Int(max=400_000, max_alarm=40_000)) - b: AttrW = AttrW(Float(min=-1, min_alarm=-0.5)) + b: AttrW = AttrW(Float(min=-1, min_alarm=-0.5), handler=SimpleAttributeSetter()) table: AttrRW = AttrRW( Table([("A", np.int32), ("B", "i"), ("C", "?"), ("D", np.float64)]) @@ -34,7 +39,7 @@ class ParentController(Controller): class ChildController(SubController): fail_on_next_e = True - c: AttrW = AttrW(Int()) + c: AttrW = AttrW(Int(), handler=SimpleAttributeSetter()) @command() async def d(self): diff --git a/tests/test_attribute.py b/tests/test_attribute.py index 473501a75..325fca792 100644 --- a/tests/test_attribute.py +++ b/tests/test_attribute.py @@ -3,7 +3,13 @@ import pytest from pytest_mock import MockerFixture -from fastcs.attributes import AttrHandlerR, AttrHandlerRW, AttrR, AttrRW, AttrW +from fastcs.attributes import ( + AttrHandlerR, + AttrHandlerRW, + AttrR, + AttrRW, + AttrW, +) from fastcs.datatypes import Int, String @@ -34,29 +40,23 @@ async def device_add(): assert ui["number"] == 2 -@pytest.mark.asyncio -async def test_simple_handler_w(mocker: MockerFixture): - attr = AttrW(Int()) - update_display_mock = mocker.patch.object(attr, "update_display_without_process") - - # This is called by the transport when it receives a put - await attr.sender.put(attr, 1) - - # The callback to update the transport display should be called - update_display_mock.assert_called_once_with(1) - - @pytest.mark.asyncio async def test_simple_handler_rw(mocker: MockerFixture): attr = AttrRW(Int()) - update_display_mock = mocker.patch.object(attr, "update_display_without_process") - set_mock = mocker.patch.object(attr, "set") + attr.update_display_without_process = mocker.MagicMock( + wraps=attr.update_display_without_process + ) + attr.set = mocker.MagicMock(wraps=attr.set) + + assert attr.sender + # This is called by the transport when it receives a put await attr.sender.put(attr, 1) - update_display_mock.assert_called_once_with(1) # The Sender of the attribute should just set the value on the attribute - set_mock.assert_awaited_once_with(1) + attr.update_display_without_process.assert_called_once_with(1) + attr.set.assert_called_once_with(1) + assert attr.get() == 1 class SimpleUpdater(AttrHandlerR):