From 264945f2fb2bd5590850b15a787a7d8246af3982 Mon Sep 17 00:00:00 2001 From: Alan Greer Date: Mon, 21 Oct 2024 15:47:15 +0100 Subject: [PATCH 1/3] Updated create_adapter_controller to select by module name rather than adapter name. Resolves issue #29. --- src/fastcs_odin/odin_controller.py | 38 +++++++++++++++++---------- tests/test_controllers.py | 41 +++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/src/fastcs_odin/odin_controller.py b/src/fastcs_odin/odin_controller.py index 7ef29be..32be618 100644 --- a/src/fastcs_odin/odin_controller.py +++ b/src/fastcs_odin/odin_controller.py @@ -24,6 +24,10 @@ class OdinController(Controller): """A root ``Controller`` for an odin control server.""" API_PREFIX = "api/0.1" + MODULE_FRAME_PROCESSOR = "FrameProcessorAdapter" + MODULE_FRAME_RECEIVER = "FrameReceiverAdapter" + MODULE_META_WRITER = "MetaListenerAdapter" + MODULE_EIGER_FAN = "EigerFanAdapter" def __init__(self, settings: IPConnectionSettings) -> None: super().__init__() @@ -50,9 +54,17 @@ async def initialise(self) -> None: response = await self.connection.get( f"{self.API_PREFIX}/{adapter}", headers=REQUEST_METADATA_HEADER ) + # Extract the module name of the adapter + match response: + case {"module": module_data}: + module = module_data["value"] + case _: + raise ValueError( + f"Did not find valid module name in response:\n{response}" + ) adapter_controller = self._create_adapter_controller( - self.connection, create_odin_parameters(response), adapter + self.connection, create_odin_parameters(response), adapter, module ) self.register_sub_controller(adapter.upper(), adapter_controller) await adapter_controller.initialise() @@ -64,32 +76,30 @@ def _create_adapter_controller( connection: HTTPConnection, parameters: list[OdinParameter], adapter: str, + module: str, ) -> OdinAdapterController: """Create a sub controller for an adapter in an odin control server.""" - match adapter: - # TODO: May not be called "fp", it is configurable in the server - case "fp": + match module: + case self.MODULE_FRAME_PROCESSOR: return FrameProcessorAdapterController( - connection, parameters, f"{self.API_PREFIX}/fp" + connection, parameters, f"{self.API_PREFIX}/{adapter}" ) - case "fr": + case self.MODULE_FRAME_RECEIVER: return FrameReceiverAdapterController( - connection, parameters, f"{self.API_PREFIX}/fr" + connection, parameters, f"{self.API_PREFIX}/{adapter}" ) - case "mw": + case self.MODULE_META_WRITER: return MetaWriterAdapterController( - connection, parameters, f"{self.API_PREFIX}/mw" + connection, parameters, f"{self.API_PREFIX}/{adapter}" ) - case "ef": + case self.MODULE_EIGER_FAN: return EigerFanAdapterController( - connection, parameters, f"{self.API_PREFIX}/ef" + connection, parameters, f"{self.API_PREFIX}/{adapter}" ) case _: return OdinAdapterController( - connection, - parameters, - f"{self.API_PREFIX}/{adapter}", + connection, parameters, f"{self.API_PREFIX}/{adapter}" ) async def connect(self) -> None: diff --git a/tests/test_controllers.py b/tests/test_controllers.py index 80c7677..5fd33f6 100644 --- a/tests/test_controllers.py +++ b/tests/test_controllers.py @@ -3,19 +3,27 @@ import pytest from fastcs.attributes import AttrR, AttrRW +from fastcs.connections.ip_connection import IPConnectionSettings from fastcs.datatypes import Bool, Float, Int from pytest_mock import MockerFixture +from fastcs_odin.eiger_fan import EigerFanAdapterController from fastcs_odin.http_connection import HTTPConnection +from fastcs_odin.meta_writer import MetaWriterAdapterController from fastcs_odin.odin_adapter_controller import ( ConfigFanSender, ParamTreeHandler, StatusSummaryUpdater, ) -from fastcs_odin.odin_controller import OdinAdapterController +from fastcs_odin.odin_controller import ( + OdinAdapterController, + OdinController, +) from fastcs_odin.odin_data import ( + FrameProcessorAdapterController, FrameProcessorController, FrameProcessorPluginController, + FrameReceiverAdapterController, FrameReceiverController, FrameReceiverDecoderController, ) @@ -66,6 +74,37 @@ def test_fp_process_parameters(): ] +@pytest.mark.asyncio +async def test_create_adapter_controller(mocker: MockerFixture): + controller = OdinController(IPConnectionSettings("", 0)) + controller.connection = mocker.AsyncMock() + + ctrl = controller._create_adapter_controller( + controller.connection, None, "fp", "FrameProcessorAdapter" + ) + assert isinstance(ctrl, FrameProcessorAdapterController) + + ctrl = controller._create_adapter_controller( + controller.connection, None, "fr", "FrameReceiverAdapter" + ) + assert isinstance(ctrl, FrameReceiverAdapterController) + + ctrl = controller._create_adapter_controller( + controller.connection, None, "mw", "MetaListenerAdapter" + ) + assert isinstance(ctrl, MetaWriterAdapterController) + + ctrl = controller._create_adapter_controller( + controller.connection, None, "ef", "EigerFanAdapter" + ) + assert isinstance(ctrl, EigerFanAdapterController) + + ctrl = controller._create_adapter_controller( + controller.connection, None, "od", "OtherAdapter" + ) + assert isinstance(ctrl, OdinAdapterController) + + @pytest.mark.asyncio async def test_fp_create_plugin_sub_controllers(): parameters = [ From 1c5afbcaa25c817422cce175687eb689416edb27 Mon Sep 17 00:00:00 2001 From: Alan Greer Date: Tue, 22 Oct 2024 13:39:20 +0000 Subject: [PATCH 2/3] Fixed linting errors --- src/fastcs_odin/odin_controller.py | 4 ++-- tests/test_controllers.py | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/fastcs_odin/odin_controller.py b/src/fastcs_odin/odin_controller.py index 32be618..6cc3605 100644 --- a/src/fastcs_odin/odin_controller.py +++ b/src/fastcs_odin/odin_controller.py @@ -56,8 +56,8 @@ async def initialise(self) -> None: ) # Extract the module name of the adapter match response: - case {"module": module_data}: - module = module_data["value"] + case {"module": {"value": str() as module}}: + pass case _: raise ValueError( f"Did not find valid module name in response:\n{response}" diff --git a/tests/test_controllers.py b/tests/test_controllers.py index 5fd33f6..47317b2 100644 --- a/tests/test_controllers.py +++ b/tests/test_controllers.py @@ -78,29 +78,30 @@ def test_fp_process_parameters(): async def test_create_adapter_controller(mocker: MockerFixture): controller = OdinController(IPConnectionSettings("", 0)) controller.connection = mocker.AsyncMock() + parameters = [OdinParameter(["0"], metadata={})] ctrl = controller._create_adapter_controller( - controller.connection, None, "fp", "FrameProcessorAdapter" + controller.connection, parameters, "fp", "FrameProcessorAdapter" ) assert isinstance(ctrl, FrameProcessorAdapterController) ctrl = controller._create_adapter_controller( - controller.connection, None, "fr", "FrameReceiverAdapter" + controller.connection, parameters, "fr", "FrameReceiverAdapter" ) assert isinstance(ctrl, FrameReceiverAdapterController) ctrl = controller._create_adapter_controller( - controller.connection, None, "mw", "MetaListenerAdapter" + controller.connection, parameters, "mw", "MetaListenerAdapter" ) assert isinstance(ctrl, MetaWriterAdapterController) ctrl = controller._create_adapter_controller( - controller.connection, None, "ef", "EigerFanAdapter" + controller.connection, parameters, "ef", "EigerFanAdapter" ) assert isinstance(ctrl, EigerFanAdapterController) ctrl = controller._create_adapter_controller( - controller.connection, None, "od", "OtherAdapter" + controller.connection, parameters, "od", "OtherAdapter" ) assert isinstance(ctrl, OdinAdapterController) From 83941d3f3771f62263c9693c4a02bd280763188c Mon Sep 17 00:00:00 2001 From: Alan Greer Date: Tue, 22 Oct 2024 14:21:41 +0000 Subject: [PATCH 3/3] Added an AdapterType enum. --- src/fastcs_odin/odin_controller.py | 14 +++++--------- src/fastcs_odin/util.py | 8 ++++++++ tests/test_controllers.py | 10 +++++----- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/fastcs_odin/odin_controller.py b/src/fastcs_odin/odin_controller.py index 6cc3605..aadbb47 100644 --- a/src/fastcs_odin/odin_controller.py +++ b/src/fastcs_odin/odin_controller.py @@ -10,7 +10,7 @@ FrameProcessorAdapterController, FrameReceiverAdapterController, ) -from fastcs_odin.util import OdinParameter, create_odin_parameters +from fastcs_odin.util import AdapterType, OdinParameter, create_odin_parameters types = {"float": Float(), "int": Int(), "bool": Bool(), "str": String()} @@ -24,10 +24,6 @@ class OdinController(Controller): """A root ``Controller`` for an odin control server.""" API_PREFIX = "api/0.1" - MODULE_FRAME_PROCESSOR = "FrameProcessorAdapter" - MODULE_FRAME_RECEIVER = "FrameReceiverAdapter" - MODULE_META_WRITER = "MetaListenerAdapter" - MODULE_EIGER_FAN = "EigerFanAdapter" def __init__(self, settings: IPConnectionSettings) -> None: super().__init__() @@ -81,19 +77,19 @@ def _create_adapter_controller( """Create a sub controller for an adapter in an odin control server.""" match module: - case self.MODULE_FRAME_PROCESSOR: + case AdapterType.FRAME_PROCESSOR: return FrameProcessorAdapterController( connection, parameters, f"{self.API_PREFIX}/{adapter}" ) - case self.MODULE_FRAME_RECEIVER: + case AdapterType.FRAME_RECEIVER: return FrameReceiverAdapterController( connection, parameters, f"{self.API_PREFIX}/{adapter}" ) - case self.MODULE_META_WRITER: + case AdapterType.META_WRITER: return MetaWriterAdapterController( connection, parameters, f"{self.API_PREFIX}/{adapter}" ) - case self.MODULE_EIGER_FAN: + case AdapterType.EIGER_FAN: return EigerFanAdapterController( connection, parameters, f"{self.API_PREFIX}/{adapter}" ) diff --git a/src/fastcs_odin/util.py b/src/fastcs_odin/util.py index 9e96825..310e2f1 100644 --- a/src/fastcs_odin/util.py +++ b/src/fastcs_odin/util.py @@ -1,5 +1,6 @@ from collections.abc import Callable, Iterator, Mapping from dataclasses import dataclass, field +from enum import Enum from typing import Any, TypeVar @@ -7,6 +8,13 @@ def is_metadata_object(v: Any) -> bool: return isinstance(v, dict) and "writeable" in v and "type" in v +class AdapterType(str, Enum): + FRAME_PROCESSOR = "FrameProcessorAdapter" + FRAME_RECEIVER = "FrameReceiverAdapter" + META_WRITER = "MetaListenerAdapter" + EIGER_FAN = "EigerFanAdapter" + + @dataclass class OdinParameter: uri: list[str] diff --git a/tests/test_controllers.py b/tests/test_controllers.py index 47317b2..fc78b36 100644 --- a/tests/test_controllers.py +++ b/tests/test_controllers.py @@ -27,7 +27,7 @@ FrameReceiverController, FrameReceiverDecoderController, ) -from fastcs_odin.util import OdinParameter +from fastcs_odin.util import AdapterType, OdinParameter HERE = Path(__file__).parent @@ -81,22 +81,22 @@ async def test_create_adapter_controller(mocker: MockerFixture): parameters = [OdinParameter(["0"], metadata={})] ctrl = controller._create_adapter_controller( - controller.connection, parameters, "fp", "FrameProcessorAdapter" + controller.connection, parameters, "fp", AdapterType.FRAME_PROCESSOR ) assert isinstance(ctrl, FrameProcessorAdapterController) ctrl = controller._create_adapter_controller( - controller.connection, parameters, "fr", "FrameReceiverAdapter" + controller.connection, parameters, "fr", AdapterType.FRAME_RECEIVER ) assert isinstance(ctrl, FrameReceiverAdapterController) ctrl = controller._create_adapter_controller( - controller.connection, parameters, "mw", "MetaListenerAdapter" + controller.connection, parameters, "mw", AdapterType.META_WRITER ) assert isinstance(ctrl, MetaWriterAdapterController) ctrl = controller._create_adapter_controller( - controller.connection, parameters, "ef", "EigerFanAdapter" + controller.connection, parameters, "ef", AdapterType.EIGER_FAN ) assert isinstance(ctrl, EigerFanAdapterController)