From 67d5154754a9e4d594cf5286d68658494c3ef737 Mon Sep 17 00:00:00 2001 From: James Souter Date: Mon, 9 Dec 2024 09:23:09 +0000 Subject: [PATCH] review comments, fix ioc entrypoint and config fan out --- src/fastcs_odin/__main__.py | 16 ++++++++++----- src/fastcs_odin/odin_adapter_controller.py | 17 +++++++--------- src/fastcs_odin/odin_data.py | 23 +++++++--------------- tests/test_controllers.py | 4 +--- 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/fastcs_odin/__main__.py b/src/fastcs_odin/__main__.py index b18b648..5260730 100644 --- a/src/fastcs_odin/__main__.py +++ b/src/fastcs_odin/__main__.py @@ -4,7 +4,11 @@ import typer from fastcs.connections.ip_connection import IPConnectionSettings from fastcs.launch import FastCS -from fastcs.transport.epics.options import EpicsGUIOptions, EpicsOptions +from fastcs.transport.epics.options import ( + EpicsGUIOptions, + EpicsIOCOptions, + EpicsOptions, +) from fastcs_odin.odin_controller import OdinController @@ -43,15 +47,17 @@ def main( @app.command() def ioc(pv_prefix: str = typer.Argument(), ip: str = OdinIp, port: int = OdinPort): - # from fastcs.backends.epics.backend import EpicsBackend - controller = OdinController(IPConnectionSettings(ip, port)) options = EpicsOptions( + ioc=EpicsIOCOptions(pv_prefix=pv_prefix), gui=EpicsGUIOptions( output_path=Path.cwd() / "odin.bob", title=f"Odin - {pv_prefix}" - ) + ), ) - FastCS(controller, options) + launcher = FastCS(controller, options) + launcher.create_docs() + launcher.create_gui() + launcher.run() # test with: python -m fastcs_odin diff --git a/src/fastcs_odin/odin_adapter_controller.py b/src/fastcs_odin/odin_adapter_controller.py index b38dfb2..c60744c 100644 --- a/src/fastcs_odin/odin_adapter_controller.py +++ b/src/fastcs_odin/odin_adapter_controller.py @@ -2,7 +2,7 @@ import re from collections.abc import Callable, Iterable, Sequence from dataclasses import dataclass -from typing import Any, Generic, TypeVar +from typing import Any from fastcs.attributes import AttrR, AttrRW, AttrW, Handler, Sender, Updater from fastcs.controller import BaseController, SubController @@ -59,11 +59,8 @@ async def update( logging.error("Update loop failed for %s:\n%s", self.path, e) -T = TypeVar("T") - - @dataclass -class StatusSummaryUpdater(Updater, Generic[T]): +class StatusSummaryUpdater(Updater): """Updater to accumulate underlying attributes into a high-level summary. Args: @@ -79,13 +76,13 @@ class StatusSummaryUpdater(Updater, Generic[T]): path_filter: list[str | tuple[str] | re.Pattern] attribute_name: str - accumulator: Callable[[Iterable[T]], T] + accumulator: Callable[[Iterable[Any]], float | int | bool | str] update_period: float | None = 0.2 async def update(self, controller: "OdinAdapterController", attr: AttrR): values = [] for sub_controller in _filter_sub_controllers(controller, self.path_filter): - sub_attribute: AttrR = getattr(sub_controller, self.attribute_name) + sub_attribute: AttrR = sub_controller.attributes[self.attribute_name] values.append(sub_attribute.get()) await attr.set(self.accumulator(values)) @@ -101,7 +98,7 @@ class ConfigFanSender(Sender): attributes: list[AttrW] - async def put(self, _: "OdinAdapterController", attr: AttrW, value: Any): # pyright: ignore[reportIncompatibleMethodOverride] + async def put(self, controller: "OdinAdapterController", attr: AttrW, value: Any): for attribute in self.attributes: await attribute.process(value) @@ -111,7 +108,7 @@ async def put(self, _: "OdinAdapterController", attr: AttrW, value: Any): # pyr def _filter_sub_controllers( controller: BaseController, path_filter: Sequence[str | tuple[str] | re.Pattern] -) -> Iterable[BaseController]: +) -> Iterable[SubController]: sub_controller_map = controller.get_sub_controllers() if len(path_filter) == 1: @@ -213,4 +210,4 @@ def _create_attributes(self): ), group=group, ) - self.attributes[parameter.name.replace(".", "")] = attr + self.attributes[parameter.name] = attr diff --git a/src/fastcs_odin/odin_data.py b/src/fastcs_odin/odin_data.py index a08a3f0..80ba35e 100644 --- a/src/fastcs_odin/odin_data.py +++ b/src/fastcs_odin/odin_data.py @@ -73,7 +73,7 @@ def _create_config_fan_attributes(self): mode, key = parameter.uri[0], parameter.uri[-1] if mode == "config" and key not in self._unique_config: try: - attr = getattr(sub_controller, parameter.name) + attr = sub_controller.attributes[parameter.name] if parameter.name not in parameter_attribute_map: parameter_attribute_map[parameter.name] = ( parameter, @@ -83,7 +83,7 @@ def _create_config_fan_attributes(self): parameter_attribute_map[parameter.name][1].append( attr ) - except AttributeError: + except KeyError: logging.warning( f"Controller has parameter {parameter}, " f"but no corresponding attribute {parameter.name}" @@ -94,14 +94,10 @@ def _create_config_fan_attributes(self): ) for parameter, sub_attributes in parameter_attribute_map.values(): - setattr( - self, - parameter.name, - sub_attributes[0].__class__( - sub_attributes[0].datatype, - group=sub_attributes[0].group, - handler=ConfigFanSender(sub_attributes), - ), + self.attributes[parameter.name] = sub_attributes[0].__class__( + sub_attributes[0].datatype, + group=sub_attributes[0].group, + handler=ConfigFanSender(sub_attributes), ) @@ -179,12 +175,7 @@ def __parameter_in_plugin( class FrameProcessorAdapterController(OdinDataAdapterController): frames_written: AttrR = AttrR( Int(), - handler=StatusSummaryUpdater( - [re.compile("FP*"), "HDF"], - "frames_written", - sum, # type: ignore - # sum does not fit accumulator type signature, casts bools to ints - ), + handler=StatusSummaryUpdater([re.compile("FP*"), "HDF"], "frames_written", sum), ) writing: AttrR = AttrR( Bool(), diff --git a/tests/test_controllers.py b/tests/test_controllers.py index dd8b818..8010037 100644 --- a/tests/test_controllers.py +++ b/tests/test_controllers.py @@ -238,9 +238,7 @@ async def test_status_summary_updater(mocker: MockerFixture): hdf_controller.frames_written.get.return_value = 50 handler = StatusSummaryUpdater( - ["OD", ("FP",), re.compile("FP*"), "HDF"], - "frames_written", - sum, # type: ignore + ["OD", ("FP",), re.compile("FP*"), "HDF"], "frames_written", sum ) hdf_controller.frames_written.get.return_value = 50 await handler.update(controller, attr)