Skip to content

Commit 8110e2e

Browse files
committed
Added root_attribute
`root_attribute` is parsed on `register_sub_controller`
1 parent 6fa4e88 commit 8110e2e

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

src/fastcs/controller.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __init__(self, path: list[str] | None = None) -> None:
2626
if not hasattr(self, "attributes"):
2727
self.attributes = {}
2828
self._path: list[str] = path or []
29-
self.__sub_controller_tree: dict[str, BaseController] = {}
29+
self.__sub_controller_tree: dict[str, SubController] = {}
3030

3131
self._bind_attrs()
3232

@@ -56,7 +56,8 @@ def _bind_attrs(self) -> None:
5656
new_attribute = copy(attr)
5757
setattr(self, attr_name, new_attribute)
5858

59-
self.attributes[attr_name] = new_attribute
59+
if attr_name != "root_attribute":
60+
self.attributes[attr_name] = new_attribute
6061

6162
def register_sub_controller(self, name: str, sub_controller: SubController):
6263
if name in self.__sub_controller_tree.keys():
@@ -67,7 +68,16 @@ def register_sub_controller(self, name: str, sub_controller: SubController):
6768
self.__sub_controller_tree[name] = sub_controller
6869
sub_controller.set_path(self.path + [name])
6970

70-
def get_sub_controllers(self) -> dict[str, BaseController]:
71+
if isinstance(sub_controller.root_attribute, Attribute):
72+
if name in self.attributes:
73+
raise TypeError(
74+
f"Cannot set SubController `{name}` root attribute "
75+
f"on the parent controller `{type(self).__name__}` "
76+
f"as it already has an attribute of that name."
77+
)
78+
self.attributes[name] = sub_controller.root_attribute
79+
80+
def get_sub_controllers(self) -> dict[str, SubController]:
7181
return self.__sub_controller_tree
7282

7383
def get_controller_mappings(self) -> list[SingleMapping]:
@@ -99,6 +109,7 @@ def _get_single_mapping(controller: BaseController) -> SingleMapping:
99109
for name, attribute in controller.attributes.items()
100110
if attribute.enabled
101111
}
112+
102113
return SingleMapping(
103114
controller, scan_methods, put_methods, command_methods, enabled_attributes
104115
)
@@ -130,5 +141,7 @@ class SubController(BaseController):
130141
it as part of a larger device.
131142
"""
132143

144+
root_attribute: Attribute | None = None
145+
133146
def __init__(self) -> None:
134147
super().__init__()

tests/test_controller.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,36 @@ def test_attribute_parsing():
9292
assert sub_controller_mapping.attributes == {
9393
"sub_attribute": sub_controller.sub_attribute,
9494
}
95+
96+
97+
def test_attribute_in_both_class_and_get_attributes():
98+
class FailingController(Controller):
99+
duplicate_attribute = AttrR(Int())
100+
101+
def __init__(self):
102+
self.attributes = {"duplicate_attribute": AttrR(Int())}
103+
super().__init__()
104+
105+
with pytest.raises(
106+
ValueError,
107+
match=(
108+
"`FailingController` has conflicting attribute `duplicate_attribute` "
109+
"already present in the attributes dict."
110+
),
111+
):
112+
FailingController()
113+
114+
115+
def test_root_attribute():
116+
class FailingController(SomeController):
117+
sub_controller = AttrR(Int())
118+
119+
with pytest.raises(
120+
TypeError,
121+
match=(
122+
"Cannot set SubController `sub_controller` root attribute "
123+
"on the parent controller `FailingController` as it already "
124+
"has an attribute of that name."
125+
),
126+
):
127+
next(_walk_mappings(FailingController(SomeSubController())))

0 commit comments

Comments
 (0)