Skip to content

Commit 6fa4e88

Browse files
committed
Attribute parsing with Controller.attributes_
1 parent 7d602ce commit 6fa4e88

File tree

2 files changed

+80
-4
lines changed

2 files changed

+80
-4
lines changed

src/fastcs/controller.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ class SingleMapping:
1919

2020

2121
class BaseController:
22+
#! Attributes passed from the device at runtime.
23+
attributes: dict[str, Attribute]
24+
2225
def __init__(self, path: list[str] | None = None) -> None:
26+
if not hasattr(self, "attributes"):
27+
self.attributes = {}
2328
self._path: list[str] = path or []
2429
self.__sub_controller_tree: dict[str, BaseController] = {}
2530

@@ -40,9 +45,19 @@ def _bind_attrs(self) -> None:
4045
for attr_name in dir(self):
4146
attr = getattr(self, attr_name)
4247
if isinstance(attr, Attribute):
48+
if (
49+
attr_name in self.attributes
50+
and self.attributes[attr_name] is not attr
51+
):
52+
raise ValueError(
53+
f"`{type(self).__name__}` has conflicting attribute "
54+
f"`{attr_name}` already present in the attributes dict."
55+
)
4356
new_attribute = copy(attr)
4457
setattr(self, attr_name, new_attribute)
4558

59+
self.attributes[attr_name] = new_attribute
60+
4661
def register_sub_controller(self, name: str, sub_controller: SubController):
4762
if name in self.__sub_controller_tree.keys():
4863
raise ValueError(
@@ -69,7 +84,6 @@ def _get_single_mapping(controller: BaseController) -> SingleMapping:
6984
scan_methods: dict[str, Scan] = {}
7085
put_methods: dict[str, Put] = {}
7186
command_methods: dict[str, Command] = {}
72-
attributes: dict[str, Attribute] = {}
7387
for attr_name in dir(controller):
7488
attr = getattr(controller, attr_name)
7589
match attr:
@@ -79,11 +93,14 @@ def _get_single_mapping(controller: BaseController) -> SingleMapping:
7993
scan_methods[attr_name] = scan_method
8094
case WrappedMethod(fastcs_method=Command(enabled=True) as command_method):
8195
command_methods[attr_name] = command_method
82-
case Attribute(enabled=True):
83-
attributes[attr_name] = attr
8496

97+
enabled_attributes = {
98+
name: attribute
99+
for name, attribute in controller.attributes.items()
100+
if attribute.enabled
101+
}
85102
return SingleMapping(
86-
controller, scan_methods, put_methods, command_methods, attributes
103+
controller, scan_methods, put_methods, command_methods, enabled_attributes
87104
)
88105

89106

tests/test_controller.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import pytest
22

3+
from fastcs.attributes import AttrR
34
from fastcs.controller import (
45
Controller,
56
SubController,
67
_get_single_mapping,
78
_walk_mappings,
89
)
10+
from fastcs.datatypes import Int
911

1012

1113
def test_controller_nesting():
@@ -33,3 +35,60 @@ def test_controller_nesting():
3335
ValueError, match=r"SubController is already registered under .*"
3436
):
3537
controller.register_sub_controller("c", sub_controller)
38+
39+
40+
class SomeSubController(SubController):
41+
def __init__(self):
42+
super().__init__()
43+
44+
sub_attribute = AttrR(Int())
45+
46+
root_attribute = AttrR(Int())
47+
48+
49+
class SomeController(Controller):
50+
annotated_attr = AttrR(Int())
51+
annotated_attr_not_defined_in_init: AttrR[int]
52+
equal_attr = AttrR(Int())
53+
annotated_and_equal_attr: AttrR[int] = AttrR(Int())
54+
55+
def __init__(self, sub_controller: SubController):
56+
self.attributes = {}
57+
58+
self.annotated_attr = AttrR(Int())
59+
self.attr_on_object = AttrR(Int())
60+
61+
self.attributes["_attributes_attr"] = AttrR(Int())
62+
self.attributes["_attributes_attr_equal"] = self.equal_attr
63+
64+
super().__init__()
65+
self.register_sub_controller("sub_controller", sub_controller)
66+
67+
68+
def test_attribute_parsing():
69+
sub_controller = SomeSubController()
70+
controller = SomeController(sub_controller)
71+
72+
mapping_walk = _walk_mappings(controller)
73+
74+
controller_mapping = next(mapping_walk)
75+
assert set(controller_mapping.attributes.keys()) == {
76+
"_attributes_attr",
77+
"annotated_attr",
78+
"attr_on_object",
79+
"_attributes_attr_equal",
80+
"annotated_and_equal_attr",
81+
"equal_attr",
82+
"sub_controller",
83+
}
84+
85+
assert SomeController.equal_attr is not controller.equal_attr
86+
assert (
87+
SomeController.annotated_and_equal_attr
88+
is not controller.annotated_and_equal_attr
89+
)
90+
91+
sub_controller_mapping = next(mapping_walk)
92+
assert sub_controller_mapping.attributes == {
93+
"sub_attribute": sub_controller.sub_attribute,
94+
}

0 commit comments

Comments
 (0)