Skip to content

Commit 4d09743

Browse files
committed
Added root_attribute
`root_attribute` is parsed on `register_sub_controller`
1 parent 4d9e130 commit 4d09743

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
@@ -27,7 +27,7 @@ def __init__(self, path: list[str] | None = None) -> None:
2727
if not hasattr(self, "attributes"):
2828
self.attributes = {}
2929
self._path: list[str] = path or []
30-
self.__sub_controller_tree: dict[str, BaseController] = {}
30+
self.__sub_controller_tree: dict[str, SubController] = {}
3131

3232
self._bind_attrs()
3333

@@ -60,7 +60,8 @@ def _bind_attrs(self) -> None:
6060
new_attribute = copy(attr)
6161
setattr(self, attr_name, new_attribute)
6262

63-
self.attributes[attr_name] = new_attribute
63+
if attr_name != "root_attribute":
64+
self.attributes[attr_name] = new_attribute
6465

6566
def register_sub_controller(self, name: str, sub_controller: SubController):
6667
if name in self.__sub_controller_tree.keys():
@@ -71,7 +72,16 @@ def register_sub_controller(self, name: str, sub_controller: SubController):
7172
self.__sub_controller_tree[name] = sub_controller
7273
sub_controller.set_path(self.path + [name])
7374

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

7787
def get_controller_mappings(self) -> list[SingleMapping]:
@@ -103,6 +113,7 @@ def _get_single_mapping(controller: BaseController) -> SingleMapping:
103113
for name, attribute in controller.attributes.items()
104114
if attribute.enabled
105115
}
116+
106117
return SingleMapping(
107118
controller, scan_methods, put_methods, command_methods, enabled_attributes
108119
)
@@ -134,5 +145,7 @@ class SubController(BaseController):
134145
it as part of a larger device.
135146
"""
136147

148+
root_attribute: Attribute | None = None
149+
137150
def __init__(self) -> None:
138151
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)