Skip to content

Commit 6756c68

Browse files
committed
Added root_attribute
`root_attribute` is parsed on `register_sub_controller`
1 parent 4299899 commit 6756c68

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
@@ -91,3 +91,36 @@ def test_attribute_parsing():
9191
assert sub_controller_mapping.attributes == {
9292
"sub_attribute": sub_controller.sub_attribute,
9393
}
94+
95+
96+
def test_attribute_in_both_class_and_get_attributes():
97+
class FailingController(Controller):
98+
duplicate_attribute = AttrR(Int())
99+
100+
def __init__(self):
101+
self.attributes = {"duplicate_attribute": AttrR(Int())}
102+
super().__init__()
103+
104+
with pytest.raises(
105+
ValueError,
106+
match=(
107+
"`FailingController` has conflicting attribute `duplicate_attribute` "
108+
"already present in the attributes dict."
109+
),
110+
):
111+
FailingController()
112+
113+
114+
def test_root_attribute():
115+
class FailingController(SomeController):
116+
sub_controller = AttrR(Int())
117+
118+
with pytest.raises(
119+
TypeError,
120+
match=(
121+
"Cannot set SubController `sub_controller` root attribute "
122+
"on the parent controller `FailingController` as it already "
123+
"has an attribute of that name."
124+
),
125+
):
126+
next(_walk_mappings(FailingController(SomeSubController())))

0 commit comments

Comments
 (0)