Skip to content

Commit

Permalink
Add SimpleHandler to make minimal Attributes functional
Browse files Browse the repository at this point in the history
This allows creating Attributes without a Handler for parameters that
are only used for internal controller logic and not sent directly to a
device.
  • Loading branch information
GDYendell committed Dec 10, 2024
1 parent 2153173 commit d789693
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 3 deletions.
21 changes: 19 additions & 2 deletions src/fastcs/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ class Handler(Sender, Updater, Protocol):
pass


class SimpleHandler(Handler):
"""Handler for internal parameters"""

async def put(self, controller: Any, attr: AttrW, value: Any):
await attr.update_display_without_process(value)

if isinstance(attr, AttrRW):
await attr.set(value)

async def update(self, controller: Any, attr: AttrR):
raise RuntimeError("SimpleHandler cannot update")

Check warning on line 54 in src/fastcs/attributes.py

View check run for this annotation

Codecov / codecov/patch

src/fastcs/attributes.py#L54

Added line #L54 was not covered by tests


class Attribute(Generic[T]):
"""Base FastCS attribute.
Expand Down Expand Up @@ -171,7 +184,11 @@ def __init__(
)
self._process_callback: AttrCallback[T] | None = None
self._write_display_callback: AttrCallback[T] | None = None
self._sender = handler

if handler is not None:
self._sender = handler
else:
self._sender = SimpleHandler()

async def process(self, value: T) -> None:
await self.process_without_display_update(value)
Expand All @@ -195,7 +212,7 @@ def set_write_display_callback(self, callback: AttrCallback[T] | None) -> None:
self._write_display_callback = callback

@property
def sender(self) -> Sender | None:
def sender(self) -> Sender:
return self._sender


Expand Down
28 changes: 27 additions & 1 deletion tests/test_attribute.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from functools import partial

import pytest
from pytest_mock import MockerFixture

from fastcs.attributes import AttrR, AttrRW
from fastcs.attributes import AttrR, AttrRW, AttrW
from fastcs.datatypes import Int, String


Expand Down Expand Up @@ -31,3 +32,28 @@ async def device_add():
await attr_rw.process(2)
assert device["number"] == 2
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(mocker.ANY, 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")

await attr.sender.put(mocker.ANY, 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)

0 comments on commit d789693

Please sign in to comment.