From 9bc1000c740e6f59a9a9461021888da6f93d3607 Mon Sep 17 00:00:00 2001 From: Rose Yemelyanova Date: Mon, 24 Jul 2023 10:09:52 +0000 Subject: [PATCH 1/5] Add children property to a device --- ophyd/v2/core.py | 70 +++++++++++++++---------------------- ophyd/v2/tests/test_core.py | 15 ++++++-- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/ophyd/v2/core.py b/ophyd/v2/core.py index 559c41d75..7339ff746 100644 --- a/ophyd/v2/core.py +++ b/ophyd/v2/core.py @@ -155,6 +155,12 @@ def name(self) -> str: """Return the name of the Device""" return self._name + @property + def children(self) -> Generator[Tuple[str, Device], None, None]: + for attr_name, attr in self.__dict__.items(): + if attr_name != "parent" and isinstance(attr, Device): + yield attr_name, attr + def set_name(self, name: str): """Set ``self.name=name`` and each ``self.child.name=name+"-child"``. @@ -164,7 +170,10 @@ def set_name(self, name: str): New name to set """ self._name = name - name_children(self, name) + for attr_name, child in self.children: + child_name = f"{name}-{attr_name.rstrip('_')}" if name else "" + child.set_name(child_name) + child.parent = self async def connect(self, sim: bool = False): """Connect self and all child Devices. @@ -174,7 +183,11 @@ async def connect(self, sim: bool = False): sim: If True then connect in simulation mode. """ - await connect_children(self, sim) + coros = { + name: child_device.connect(sim) for name, child_device in self.children + } + if coros: + await wait_for_connection(**coros) class NotConnected(Exception): @@ -217,37 +230,6 @@ async def wait_for_connection(**coros: Awaitable[None]): await f -async def connect_children(device: Device, sim: bool): - """Call ``child.connect(sim)`` on all child devices in parallel. - - Typically used to implement `Device.connect` like this:: - - async def connect(self, sim=False): - await connect_children(self, sim) - """ - - coros = { - name: child_device.connect(sim) - for name, child_device in get_device_children(device) - } - if coros: - await wait_for_connection(**coros) - - -def name_children(device: Device, name: str): - """Call ``child.set_name(child_name)`` on all child devices in series.""" - for attr_name, child in get_device_children(device): - child_name = f"{name}-{attr_name.rstrip('_')}" if name else "" - child.set_name(child_name) - child.parent = device - - -def get_device_children(device: Device) -> Generator[Tuple[str, Device], None, None]: - for attr_name, attr in device.__dict__.items(): - if attr_name != "parent" and isinstance(attr, Device): - yield attr_name, attr - - class DeviceCollector: """Collector of top level Device instances to be used as a context manager @@ -981,15 +963,21 @@ async def read(self) -> Dict[str, Reading]: class DeviceVector(Dict[int, VT], Device): - def set_name(self, parent_name: str): - self._name = parent_name - for name, device in self.items(): - device.set_name(f"{parent_name}-{name}") - device.parent = self + # def set_name(self, parent_name: str): + # self._name = parent_name + # for name, device in self.items(): + # device.set_name(f"{parent_name}-{name}") + # device.parent = self - async def connect(self, sim: bool = False): - coros = {str(k): d.connect(sim) for k, d in self.items()} - await wait_for_connection(**coros) + @property + def children(self) -> Generator[Tuple[str, Device], None, None]: + for attr_name, attr in self.items(): + if isinstance(attr, Device): + yield str(attr_name), attr + + # async def connect(self, sim: bool = False): + # coros = {str(k): d.connect(sim) for k, d in self.items()} + # await wait_for_connection(**coros) def get_unique(values: Dict[str, T], types: str) -> T: diff --git a/ophyd/v2/tests/test_core.py b/ophyd/v2/tests/test_core.py index aa2566151..3c88745d7 100644 --- a/ophyd/v2/tests/test_core.py +++ b/ophyd/v2/tests/test_core.py @@ -23,7 +23,6 @@ SignalRW, SimSignalBackend, T, - get_device_children, set_and_wait_for_value, set_sim_put_proceeds, set_sim_value, @@ -205,17 +204,27 @@ def __init__(self, name: str) -> None: self.set_name(name) -def test_get_device_children(): +def test_device_children(): parent = DummyDeviceGroup("parent") names = ["child1", "child2", "dict_with_children"] - for idx, (name, child) in enumerate(get_device_children(parent)): + for idx, (name, child) in enumerate(parent.children): assert name == names[idx] assert ( type(child) == DummyBaseDevice if name.startswith("child") else type(child) == DeviceVector ) + assert child.parent == parent + + +def test_device_vector_children(): + parent = DummyDeviceGroup("root") + + device_vector_children = [ + (name, child) for name, child in parent.dict_with_children.children + ] + assert device_vector_children == [("123", parent.dict_with_children[123])] async def test_children_of_device_have_set_names_and_get_connected(): From 1e6659d9f2ca817ef30046929859d5e9a0cb21e1 Mon Sep 17 00:00:00 2001 From: Rose Yemelyanova Date: Mon, 24 Jul 2023 10:16:12 +0000 Subject: [PATCH 2/5] Remove unnecessary comments --- ophyd/v2/core.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ophyd/v2/core.py b/ophyd/v2/core.py index 7339ff746..2ec6d32d5 100644 --- a/ophyd/v2/core.py +++ b/ophyd/v2/core.py @@ -963,22 +963,12 @@ async def read(self) -> Dict[str, Reading]: class DeviceVector(Dict[int, VT], Device): - # def set_name(self, parent_name: str): - # self._name = parent_name - # for name, device in self.items(): - # device.set_name(f"{parent_name}-{name}") - # device.parent = self - @property def children(self) -> Generator[Tuple[str, Device], None, None]: for attr_name, attr in self.items(): if isinstance(attr, Device): yield str(attr_name), attr - # async def connect(self, sim: bool = False): - # coros = {str(k): d.connect(sim) for k, d in self.items()} - # await wait_for_connection(**coros) - def get_unique(values: Dict[str, T], types: str) -> T: """If all values are the same, return that value, otherwise return TypeError From 7304c16903449a517d10c19665aaf6b63586b3c1 Mon Sep 17 00:00:00 2001 From: Rose Yemelyanova <90774497+RAYemelyanova@users.noreply.github.com> Date: Tue, 1 Aug 2023 13:51:26 +0100 Subject: [PATCH 3/5] Simplify children property typing on Device Co-authored-by: Tom C (DLS) <101418278+coretl@users.noreply.github.com> --- ophyd/v2/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ophyd/v2/core.py b/ophyd/v2/core.py index 2ec6d32d5..acd2d4791 100644 --- a/ophyd/v2/core.py +++ b/ophyd/v2/core.py @@ -156,7 +156,7 @@ def name(self) -> str: return self._name @property - def children(self) -> Generator[Tuple[str, Device], None, None]: + def children(self) -> Iterator[Tuple[str, Device]]: for attr_name, attr in self.__dict__.items(): if attr_name != "parent" and isinstance(attr, Device): yield attr_name, attr From 1108313a8a41fed3108ee8eb90ea15f6de888b3a Mon Sep 17 00:00:00 2001 From: Rose Yemelyanova Date: Tue, 1 Aug 2023 12:55:05 +0000 Subject: [PATCH 4/5] Made Device.children a method instead of a property --- ophyd/v2/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ophyd/v2/core.py b/ophyd/v2/core.py index acd2d4791..1a47fe58f 100644 --- a/ophyd/v2/core.py +++ b/ophyd/v2/core.py @@ -23,6 +23,7 @@ Generator, Generic, Iterable, + Iterator, List, Optional, Sequence, @@ -155,7 +156,6 @@ def name(self) -> str: """Return the name of the Device""" return self._name - @property def children(self) -> Iterator[Tuple[str, Device]]: for attr_name, attr in self.__dict__.items(): if attr_name != "parent" and isinstance(attr, Device): @@ -170,7 +170,7 @@ def set_name(self, name: str): New name to set """ self._name = name - for attr_name, child in self.children: + for attr_name, child in self.children(): child_name = f"{name}-{attr_name.rstrip('_')}" if name else "" child.set_name(child_name) child.parent = self @@ -184,7 +184,7 @@ async def connect(self, sim: bool = False): If True then connect in simulation mode. """ coros = { - name: child_device.connect(sim) for name, child_device in self.children + name: child_device.connect(sim) for name, child_device in self.children() } if coros: await wait_for_connection(**coros) From b1ae733d3f6fbe51fdc2d5e4b3e590c98d02d180 Mon Sep 17 00:00:00 2001 From: Rose Yemelyanova Date: Tue, 1 Aug 2023 13:06:46 +0000 Subject: [PATCH 5/5] Modify DeviceVector in line with children now being a method, not a property --- ophyd/v2/core.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ophyd/v2/core.py b/ophyd/v2/core.py index 1a47fe58f..51de69640 100644 --- a/ophyd/v2/core.py +++ b/ophyd/v2/core.py @@ -963,7 +963,6 @@ async def read(self) -> Dict[str, Reading]: class DeviceVector(Dict[int, VT], Device): - @property def children(self) -> Generator[Tuple[str, Device], None, None]: for attr_name, attr in self.items(): if isinstance(attr, Device):