|
| 1 | +import asyncio |
1 | 2 | import enum |
2 | 3 |
|
3 | 4 | import numpy as np |
4 | 5 | import pytest |
5 | 6 | from pvi.device import SignalR |
6 | 7 | from pydantic import ValidationError |
7 | 8 |
|
8 | | -from fastcs.attributes import AttrR, AttrRW |
| 9 | +from fastcs.attributes import Attribute, AttrR, AttrRW |
9 | 10 | from fastcs.controller import Controller |
10 | 11 | from fastcs.datatypes import Bool, Enum, Float, Int, String |
| 12 | +from fastcs.launch import FastCS |
11 | 13 | from fastcs.util import ( |
12 | 14 | numpy_to_fastcs_datatype, |
13 | 15 | snake_to_pascal, |
@@ -136,3 +138,57 @@ class ControllerWrongEnumClass(Controller): |
136 | 138 | "'hinted_enum' does not match defined datatype. " |
137 | 139 | "Expected 'MyEnum', got 'MyEnum2'." |
138 | 140 | ) |
| 141 | + |
| 142 | + |
| 143 | +def test_hinted_attributes_verified_on_subcontrollers(): |
| 144 | + loop = asyncio.get_event_loop() |
| 145 | + |
| 146 | + class ControllerWithWrongType(Controller): |
| 147 | + hinted_missing: AttrR[int] |
| 148 | + |
| 149 | + async def connect(self): |
| 150 | + return |
| 151 | + |
| 152 | + class TopController(Controller): |
| 153 | + async def initialise(self): # why does this not get called? |
| 154 | + subcontroller = ControllerWithWrongType() |
| 155 | + self.add_sub_controller("MySubController", subcontroller) |
| 156 | + |
| 157 | + fastcs = FastCS(TopController(), [], loop) |
| 158 | + with pytest.raises(RuntimeError, match="failed to introspect hinted attribute"): |
| 159 | + fastcs.run() |
| 160 | + |
| 161 | + |
| 162 | +def test_hinted_attribute_access_mode_verified(): |
| 163 | + # test verification works with non-GenericAlias type hints |
| 164 | + loop = asyncio.get_event_loop() |
| 165 | + |
| 166 | + class ControllerAttrWrongAccessMode(Controller): |
| 167 | + read_attr: AttrR |
| 168 | + |
| 169 | + async def initialise(self): |
| 170 | + self.read_attr = AttrRW(Int()) |
| 171 | + |
| 172 | + fastcs = FastCS(ControllerAttrWrongAccessMode(), [], loop) |
| 173 | + with pytest.raises(RuntimeError, match="does not match defined access mode"): |
| 174 | + fastcs.run() |
| 175 | + |
| 176 | + |
| 177 | +@pytest.mark.asyncio |
| 178 | +async def test_hinted_attributes_with_unspecified_access_mode(): |
| 179 | + class ControllerUnspecifiedAccessMode(Controller): |
| 180 | + unspecified_access_mode: Attribute |
| 181 | + |
| 182 | + async def initialise(self): |
| 183 | + self.unspecified_access_mode = AttrRW(Int()) |
| 184 | + |
| 185 | + controller = ControllerUnspecifiedAccessMode() |
| 186 | + await controller.initialise() |
| 187 | + # no assertion thrown |
| 188 | + with pytest.raises( |
| 189 | + RuntimeError, |
| 190 | + match=( |
| 191 | + "does not match defined access mode. Expected 'Attribute', got 'AttrRW'" |
| 192 | + ), |
| 193 | + ): |
| 194 | + validate_hinted_attributes(controller) |
0 commit comments