Skip to content

Commit be34c33

Browse files
committed
Resolving merge conflicts
2 parents 889ceec + e926a60 commit be34c33

File tree

5 files changed

+78
-1
lines changed

5 files changed

+78
-1
lines changed

src/ophyd_async/core/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
soft_signal_r_and_setter,
5050
soft_signal_rw,
5151
wait_for_value,
52+
walk_config_signals,
5253
walk_rw_signals,
5354
)
5455
from ._signal_backend import (
@@ -131,6 +132,7 @@
131132
"set_and_wait_for_value",
132133
"set_and_wait_for_other_value",
133134
"walk_rw_signals",
135+
"walk_config_signals",
134136
# Readable
135137
"StandardReadable",
136138
"StandardReadableFormat",

src/ophyd_async/core/_signal.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import asyncio
44
import functools
5+
import inspect
56
import time
67
from collections.abc import AsyncGenerator, Awaitable, Callable
78
from typing import Any, Generic, cast
89

910
from bluesky.protocols import (
11+
Configurable,
1012
Locatable,
1113
Location,
1214
Movable,
@@ -678,6 +680,36 @@ def walk_rw_signals(device: Device, path_prefix: str = "") -> dict[str, SignalRW
678680
return signals
679681

680682

683+
async def walk_config_signals(
684+
device: Device, path_prefix: str = ""
685+
) -> dict[str, SignalRW[Any]]:
686+
"""Retrieve all configuration signals from a device.
687+
688+
Stores retrieved signals with their dotted attribute paths in a dictionary. Used as
689+
part of saving and loading a device.
690+
691+
:param device: Device to retrieve configuration signals from.
692+
:param path_prefix: For internal use, leave blank when calling the method.
693+
:return:
694+
A dictionary matching the string attribute path of a SignalRW with the
695+
signal itself.
696+
"""
697+
signals: dict[str, SignalRW[Any]] = {}
698+
config_names: list[str] = []
699+
if isinstance(device, Configurable):
700+
configuration = device.read_configuration()
701+
if inspect.isawaitable(configuration):
702+
configuration = await configuration
703+
config_names = list(configuration.keys())
704+
for attr_name, attr in device.children():
705+
dot_path = f"{path_prefix}{attr_name}"
706+
if isinstance(attr, SignalRW) and attr.name in config_names:
707+
signals[dot_path] = attr
708+
signals.update(await walk_config_signals(attr, path_prefix=dot_path + "."))
709+
710+
return signals
711+
712+
681713
class Ignore:
682714
"""Annotation to ignore a signal when connecting a device."""
683715

src/ophyd_async/plan_stubs/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
apply_settings_if_different,
1414
get_current_settings,
1515
retrieve_settings,
16+
store_config_settings,
1617
store_settings,
1718
)
1819

@@ -29,4 +30,5 @@
2930
"get_current_settings",
3031
"retrieve_settings",
3132
"store_settings",
33+
"store_config_settings",
3234
]

src/ophyd_async/plan_stubs/_settings.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
Settings,
1414
SettingsProvider,
1515
SignalRW,
16+
walk_config_signals,
1617
walk_rw_signals,
1718
)
1819
from ophyd_async.core._table import Table
@@ -55,6 +56,21 @@ def store_settings(
5556
yield from wait_for_awaitable(provider.store(name, named_values))
5657

5758

59+
@plan
60+
def store_config_settings(
61+
provider: SettingsProvider, name: str, device: Device
62+
) -> MsgGenerator[None]:
63+
"""Walk a Device for SignalRWs and store their values.
64+
65+
:param provider: The provider to store the settings with.
66+
:param name: The name to store the settings under.
67+
:param device: The Device to walk for SignalRWs.
68+
"""
69+
signals = yield from wait_for_awaitable(walk_config_signals(device))
70+
named_values = yield from _get_values_of_signals(signals)
71+
yield from wait_for_awaitable(provider.store(name, named_values))
72+
73+
5874
@plan
5975
def retrieve_settings(
6076
provider: SettingsProvider, name: str, device: Device

tests/plan_stubs/test_settings.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,15 @@
1111
apply_settings_if_different,
1212
get_current_settings,
1313
retrieve_settings,
14+
store_config_settings,
1415
store_settings,
1516
)
16-
from ophyd_async.testing import ExampleTable, ParentOfEverythingDevice, get_mock
17+
from ophyd_async.testing import (
18+
ExampleTable,
19+
OneOfEverythingDevice,
20+
ParentOfEverythingDevice,
21+
get_mock,
22+
)
1723

1824
TEST_DATA = Path(__file__).absolute().parent.parent / "test_data"
1925

@@ -47,6 +53,25 @@ def my_plan():
4753
RE(my_plan())
4854

4955

56+
async def test_store_config_settings(
57+
RE, parent_device: OneOfEverythingDevice, tmp_path
58+
):
59+
provider = YamlSettingsProvider(tmp_path)
60+
61+
def my_plan():
62+
yield from store_config_settings(provider, "test_file", parent_device)
63+
with open(tmp_path / "test_file.yaml") as actual_file:
64+
actual_data = yaml.safe_load(actual_file)
65+
with open(TEST_DATA / "test_yaml_save.yaml") as expected_file:
66+
expected_data = yaml.safe_load(expected_file)
67+
# Remove the keys that shouldn't be expected
68+
expected_data.pop("_sig_rw", None)
69+
expected_data.pop("sig_rw", None)
70+
assert actual_data == expected_data
71+
72+
RE(my_plan())
73+
74+
5075
async def test_retrieve_and_apply_settings(RE, parent_device: ParentOfEverythingDevice):
5176
provider = YamlSettingsProvider(TEST_DATA)
5277
expected_values = await parent_device.get_signal_values()

0 commit comments

Comments
 (0)