-
Notifications
You must be signed in to change notification settings - Fork 5
Implement SubControllerVector #192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #192 +/- ##
==========================================
- Coverage 89.03% 88.58% -0.46%
==========================================
Files 46 46
Lines 2280 2321 +41
==========================================
+ Hits 2030 2056 +26
- Misses 250 265 +15 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Maybe it makes more sense to have @dataclass(frozen=True)
class VectorOrigin:
name: str
vector: weakref.ReferenceType[SubControllerVector]Then, we can dereference the parent vector if we want to do something with knowledge of what controllers are in a group, but also just pass the name to pvi since that is all we need for grouping. I'm unsure of any use cases the vector class has other than pvi grouping though, so I'm not sure is this adds any value. |
|
@shihab-dls I think the trouble of having to keep track of what vector a sub controller is part of would be avoided if Then with a controller hierarchy like the path would be ["fp", 1, "hdf"] where integers in the path are treated specially:
If this works as I would like, the FP controller vector itself could have attributes and commands. For example here There may be complications with as this, but that is how it looks in my head. Does that make some sense? Happy to pair on this and figure out the details. |
I like this idea (adopting more from ophyds |
f67f90e to
d6bfed5
Compare
At this point, pvi trees for CA and P4P are constructed such that a parent controller will have a vector entry as: within which, the vector in p4p will have whereas in ca it will have alongside any vector attributes. I'm unaware if there is a reason we don't want to do P.S. I've also just tested this in ophyd-async and a |
1c4e14c to
a8805b9
Compare
|
Unsure about codecov currently, so will request a review to make sure the pvi structure and PV formatting is what we expect |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the thing that needs to drive this design of this is what we can represent in the PVI tree. I don't think we can have a node in the tree with both named controllers and indexed controllers.
Perhaps add_sub_controller should still only take str and adding indexed controllers to ControllerVector can only be done with __setitem__? We should also disable adding named controllers to ControllerVector and disable Controller from registering controllers with just numbers as the name.
I am wondering if with these restrictions we can revert the controller path being str | int everywhere and instead have the ControllerVector validate the int and then convert it straight to a str. Here and here we are relying on path elements being int to know if it is a vector, but we could just use isdigit instead.
Thoughts?
I think that's reasonable! I've just implemented this. In order to restrict usage of where where one of the vector children has: Currently, in ophyd-async, this maps to: So now I'll need to amend ophyd-async to infer a DeviceVector based on the presence of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some initial comments. I will have to review the p4p bit in an editor to understand what it is doing...
| ) | ||
|
|
||
| def __getitem__(self, key: int) -> Controller: | ||
| return self._children[key] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to catch the KeyError here and re-raise with a better error like "Controller does not have a sub controller ".
| for index, child in children.items(): | ||
| super().add_sub_controller(str(index), child) | ||
|
|
||
| def add_sub_controller(self, *args, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think pyright won't like not having the same function signature here?
| yield str(key), child | ||
|
|
||
| def __hash__(self): | ||
| return hash(id(self)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure we need to use ControllerVector as a key. This isn't required to fulfill MutableMapping is it?
| sub_controller.set_path(self.path + [name]) | ||
| self.__sub_controller_tree[name] = sub_controller | ||
| super().__setattr__(name, sub_controller) | ||
| super().__setattr__(str(name), sub_controller) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are still a bunch of str() casts that aren't needed now that path is list[str] again
| """A collection of SubControllers, with an arbitrary integer index. | ||
| An instance of this class can be registered with a parent ``Controller`` to include | ||
| it's children as part of a larger controller. Each child of the vector will keep | ||
| a string name of the vector. | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can just be
| """A collection of SubControllers, with an arbitrary integer index. | |
| An instance of this class can be registered with a parent ``Controller`` to include | |
| it's children as part of a larger controller. Each child of the vector will keep | |
| a string name of the vector. | |
| """ | |
| """A controller with a collection of identical sub controllers distinguished by a numeric value""" |
| self.update(children) | ||
| super().__init__(description=description, ios=ios) | ||
| for index, child in children.items(): | ||
| super().add_sub_controller(str(index), child) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this hit this check?
| def add_sub_controller(self, *args, **kwargs): | ||
| raise NotImplementedError( | ||
| "Cannot add named sub controller to ControllerVector. " | ||
| "Use __setitem__ instead, for indexed sub controllers" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably need an explicit example of square brackets indexing as well as saying use __setitem__
|
|
||
| def children(self) -> Iterator[tuple[str, Controller]]: | ||
| for key, child in self._children.items(): | ||
| yield str(key), child |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be be nicer to just return the dict so that the caller can choose to do .items()/.keys()/.values() rather than having to index a tuple.
Actually, do we get in implemented for free by inheriting MutableMapping? In which case maybe we could have children just be Iterator[Controller]?
| arguments["validate"] = _verify_in_datatype | ||
| case Bool(): | ||
| arguments["ZNAM"] = "False" | ||
| arguments["ONAM"] = "True" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unrelated?
| pv_prefix: str | ||
| controller_api: ControllerAPI | None | ||
| description: str | None | ||
| device_signal_info: _PviSignalInfo | None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these are redundant?
fixes #122
This PR introduces a
SubControllerVector, which is a mapping ofinttoSubController, used in pvi grouping.