ophyd-async 0.9.0a2__py3-none-any.whl → 0.10.0a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ophyd_async/__init__.py +5 -8
- ophyd_async/_docs_parser.py +12 -0
- ophyd_async/_version.py +9 -4
- ophyd_async/core/__init__.py +97 -62
- ophyd_async/core/_derived_signal.py +271 -0
- ophyd_async/core/_derived_signal_backend.py +300 -0
- ophyd_async/core/_detector.py +106 -125
- ophyd_async/core/_device.py +69 -63
- ophyd_async/core/_device_filler.py +65 -1
- ophyd_async/core/_flyer.py +14 -5
- ophyd_async/core/_hdf_dataset.py +29 -22
- ophyd_async/core/_log.py +14 -23
- ophyd_async/core/_mock_signal_backend.py +11 -3
- ophyd_async/core/_protocol.py +65 -45
- ophyd_async/core/_providers.py +28 -9
- ophyd_async/core/_readable.py +44 -35
- ophyd_async/core/_settings.py +36 -27
- ophyd_async/core/_signal.py +262 -170
- ophyd_async/core/_signal_backend.py +56 -13
- ophyd_async/core/_soft_signal_backend.py +16 -11
- ophyd_async/core/_status.py +72 -24
- ophyd_async/core/_table.py +41 -11
- ophyd_async/core/_utils.py +96 -49
- ophyd_async/core/_yaml_settings.py +2 -0
- ophyd_async/epics/__init__.py +1 -0
- ophyd_async/epics/adandor/_andor.py +2 -2
- ophyd_async/epics/adandor/_andor_controller.py +4 -2
- ophyd_async/epics/adandor/_andor_io.py +2 -4
- ophyd_async/epics/adaravis/__init__.py +5 -0
- ophyd_async/epics/adaravis/_aravis.py +4 -8
- ophyd_async/epics/adaravis/_aravis_controller.py +20 -43
- ophyd_async/epics/adaravis/_aravis_io.py +13 -28
- ophyd_async/epics/adcore/__init__.py +23 -8
- ophyd_async/epics/adcore/_core_detector.py +42 -2
- ophyd_async/epics/adcore/_core_io.py +124 -99
- ophyd_async/epics/adcore/_core_logic.py +106 -27
- ophyd_async/epics/adcore/_core_writer.py +12 -8
- ophyd_async/epics/adcore/_hdf_writer.py +21 -38
- ophyd_async/epics/adcore/_single_trigger.py +2 -2
- ophyd_async/epics/adcore/_utils.py +2 -2
- ophyd_async/epics/adkinetix/__init__.py +2 -1
- ophyd_async/epics/adkinetix/_kinetix.py +3 -3
- ophyd_async/epics/adkinetix/_kinetix_controller.py +4 -2
- ophyd_async/epics/adkinetix/_kinetix_io.py +12 -13
- ophyd_async/epics/adpilatus/__init__.py +5 -0
- ophyd_async/epics/adpilatus/_pilatus.py +1 -1
- ophyd_async/epics/adpilatus/_pilatus_controller.py +5 -24
- ophyd_async/epics/adpilatus/_pilatus_io.py +11 -9
- ophyd_async/epics/adsimdetector/__init__.py +8 -1
- ophyd_async/epics/adsimdetector/_sim.py +4 -14
- ophyd_async/epics/adsimdetector/_sim_controller.py +17 -0
- ophyd_async/epics/adsimdetector/_sim_io.py +10 -0
- ophyd_async/epics/advimba/__init__.py +10 -1
- ophyd_async/epics/advimba/_vimba.py +3 -2
- ophyd_async/epics/advimba/_vimba_controller.py +4 -2
- ophyd_async/epics/advimba/_vimba_io.py +23 -28
- ophyd_async/epics/core/_aioca.py +35 -16
- ophyd_async/epics/core/_epics_connector.py +4 -0
- ophyd_async/epics/core/_epics_device.py +2 -0
- ophyd_async/epics/core/_p4p.py +10 -2
- ophyd_async/epics/core/_pvi_connector.py +65 -8
- ophyd_async/epics/core/_signal.py +51 -51
- ophyd_async/epics/core/_util.py +4 -4
- ophyd_async/epics/demo/__init__.py +16 -0
- ophyd_async/epics/demo/__main__.py +31 -0
- ophyd_async/epics/demo/_ioc.py +32 -0
- ophyd_async/epics/demo/_motor.py +82 -0
- ophyd_async/epics/demo/_point_detector.py +42 -0
- ophyd_async/epics/demo/_point_detector_channel.py +22 -0
- ophyd_async/epics/demo/_stage.py +15 -0
- ophyd_async/epics/{sim/mover.db → demo/motor.db} +2 -1
- ophyd_async/epics/demo/point_detector.db +59 -0
- ophyd_async/epics/demo/point_detector_channel.db +21 -0
- ophyd_async/epics/eiger/_eiger.py +1 -3
- ophyd_async/epics/eiger/_eiger_controller.py +11 -4
- ophyd_async/epics/eiger/_eiger_io.py +2 -0
- ophyd_async/epics/eiger/_odin_io.py +1 -2
- ophyd_async/epics/motor.py +65 -28
- ophyd_async/epics/signal.py +4 -1
- ophyd_async/epics/testing/_example_ioc.py +21 -9
- ophyd_async/epics/testing/_utils.py +3 -0
- ophyd_async/epics/testing/test_records.db +8 -0
- ophyd_async/epics/testing/test_records_pva.db +17 -16
- ophyd_async/fastcs/__init__.py +1 -0
- ophyd_async/fastcs/core.py +6 -0
- ophyd_async/fastcs/odin/__init__.py +1 -0
- ophyd_async/fastcs/panda/__init__.py +8 -6
- ophyd_async/fastcs/panda/_block.py +29 -9
- ophyd_async/fastcs/panda/_control.py +5 -0
- ophyd_async/fastcs/panda/_hdf_panda.py +2 -0
- ophyd_async/fastcs/panda/_table.py +9 -6
- ophyd_async/fastcs/panda/_trigger.py +23 -9
- ophyd_async/fastcs/panda/_writer.py +27 -30
- ophyd_async/plan_stubs/__init__.py +2 -0
- ophyd_async/plan_stubs/_ensure_connected.py +1 -0
- ophyd_async/plan_stubs/_fly.py +2 -4
- ophyd_async/plan_stubs/_nd_attributes.py +2 -0
- ophyd_async/plan_stubs/_panda.py +1 -0
- ophyd_async/plan_stubs/_settings.py +43 -16
- ophyd_async/plan_stubs/_utils.py +3 -0
- ophyd_async/plan_stubs/_wait_for_awaitable.py +1 -1
- ophyd_async/sim/__init__.py +24 -14
- ophyd_async/sim/__main__.py +43 -0
- ophyd_async/sim/_blob_detector.py +33 -0
- ophyd_async/sim/_blob_detector_controller.py +48 -0
- ophyd_async/sim/_blob_detector_writer.py +105 -0
- ophyd_async/sim/_mirror_horizontal.py +46 -0
- ophyd_async/sim/_mirror_vertical.py +74 -0
- ophyd_async/sim/_motor.py +233 -0
- ophyd_async/sim/_pattern_generator.py +124 -0
- ophyd_async/sim/_point_detector.py +86 -0
- ophyd_async/sim/_stage.py +19 -0
- ophyd_async/tango/__init__.py +1 -0
- ophyd_async/tango/core/__init__.py +6 -1
- ophyd_async/tango/core/_base_device.py +41 -33
- ophyd_async/tango/core/_converters.py +81 -0
- ophyd_async/tango/core/_signal.py +18 -32
- ophyd_async/tango/core/_tango_readable.py +2 -19
- ophyd_async/tango/core/_tango_transport.py +136 -60
- ophyd_async/tango/core/_utils.py +47 -0
- ophyd_async/tango/{sim → demo}/_counter.py +2 -0
- ophyd_async/tango/{sim → demo}/_detector.py +2 -0
- ophyd_async/tango/{sim → demo}/_mover.py +5 -4
- ophyd_async/tango/{sim → demo}/_tango/_servers.py +4 -0
- ophyd_async/tango/testing/__init__.py +6 -0
- ophyd_async/tango/testing/_one_of_everything.py +200 -0
- ophyd_async/testing/__init__.py +29 -7
- ophyd_async/testing/_assert.py +145 -83
- ophyd_async/testing/_mock_signal_utils.py +56 -70
- ophyd_async/testing/_one_of_everything.py +41 -21
- ophyd_async/testing/_single_derived.py +89 -0
- ophyd_async/testing/_utils.py +3 -0
- {ophyd_async-0.9.0a2.dist-info → ophyd_async-0.10.0a2.dist-info}/METADATA +25 -26
- ophyd_async-0.10.0a2.dist-info/RECORD +149 -0
- {ophyd_async-0.9.0a2.dist-info → ophyd_async-0.10.0a2.dist-info}/WHEEL +1 -1
- ophyd_async/epics/sim/__init__.py +0 -54
- ophyd_async/epics/sim/_ioc.py +0 -29
- ophyd_async/epics/sim/_mover.py +0 -101
- ophyd_async/epics/sim/_sensor.py +0 -37
- ophyd_async/epics/sim/sensor.db +0 -19
- ophyd_async/sim/_pattern_detector/__init__.py +0 -13
- ophyd_async/sim/_pattern_detector/_pattern_detector.py +0 -42
- ophyd_async/sim/_pattern_detector/_pattern_detector_controller.py +0 -69
- ophyd_async/sim/_pattern_detector/_pattern_detector_writer.py +0 -41
- ophyd_async/sim/_pattern_detector/_pattern_generator.py +0 -214
- ophyd_async/sim/_sim_motor.py +0 -107
- ophyd_async-0.9.0a2.dist-info/RECORD +0 -129
- /ophyd_async/tango/{sim → demo}/__init__.py +0 -0
- /ophyd_async/tango/{sim → demo}/_tango/__init__.py +0 -0
- {ophyd_async-0.9.0a2.dist-info → ophyd_async-0.10.0a2.dist-info/licenses}/LICENSE +0 -0
- {ophyd_async-0.9.0a2.dist-info → ophyd_async-0.10.0a2.dist-info}/top_level.txt +0 -0
ophyd_async/core/_providers.py
CHANGED
|
@@ -10,8 +10,7 @@ from typing import Protocol
|
|
|
10
10
|
|
|
11
11
|
@dataclass
|
|
12
12
|
class PathInfo:
|
|
13
|
-
"""
|
|
14
|
-
Information about where and how to write a file.
|
|
13
|
+
"""Information about where and how to write a file.
|
|
15
14
|
|
|
16
15
|
:param directory_path: Directory into which files should be written
|
|
17
16
|
:param filename: Base filename to use generated by FilenameProvider, w/o extension
|
|
@@ -25,18 +24,24 @@ class PathInfo:
|
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
class FilenameProvider(Protocol):
|
|
27
|
+
"""Base class for callable classes providing filenames."""
|
|
28
|
+
|
|
28
29
|
@abstractmethod
|
|
29
30
|
def __call__(self, device_name: str | None = None) -> str:
|
|
30
|
-
"""Get a filename to use for output data, w/o extension"""
|
|
31
|
+
"""Get a filename to use for output data, w/o extension."""
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class PathProvider(Protocol):
|
|
35
|
+
"""Abstract class that tells a detector where to write its data."""
|
|
36
|
+
|
|
34
37
|
@abstractmethod
|
|
35
38
|
def __call__(self, device_name: str | None = None) -> PathInfo:
|
|
36
|
-
"""Get the current directory to write files into"""
|
|
39
|
+
"""Get the current directory to write files into."""
|
|
37
40
|
|
|
38
41
|
|
|
39
42
|
class StaticFilenameProvider(FilenameProvider):
|
|
43
|
+
"""Provides a constant filename on every call."""
|
|
44
|
+
|
|
40
45
|
def __init__(self, filename: str):
|
|
41
46
|
self._static_filename = filename
|
|
42
47
|
|
|
@@ -45,6 +50,8 @@ class StaticFilenameProvider(FilenameProvider):
|
|
|
45
50
|
|
|
46
51
|
|
|
47
52
|
class UUIDFilenameProvider(FilenameProvider):
|
|
53
|
+
"""Files will have a UUID as a filename."""
|
|
54
|
+
|
|
48
55
|
def __init__(
|
|
49
56
|
self,
|
|
50
57
|
uuid_call_func: Callable = uuid.uuid4,
|
|
@@ -68,6 +75,8 @@ class UUIDFilenameProvider(FilenameProvider):
|
|
|
68
75
|
|
|
69
76
|
|
|
70
77
|
class AutoIncrementFilenameProvider(FilenameProvider):
|
|
78
|
+
"""Provides a new numerically incremented filename on each call."""
|
|
79
|
+
|
|
71
80
|
def __init__(
|
|
72
81
|
self,
|
|
73
82
|
base_filename: str = "",
|
|
@@ -98,14 +107,16 @@ class AutoIncrementFilenameProvider(FilenameProvider):
|
|
|
98
107
|
|
|
99
108
|
|
|
100
109
|
class StaticPathProvider(PathProvider):
|
|
110
|
+
"""All files will be within a static directory."""
|
|
111
|
+
|
|
101
112
|
def __init__(
|
|
102
113
|
self,
|
|
103
114
|
filename_provider: FilenameProvider,
|
|
104
|
-
directory_path: Path,
|
|
115
|
+
directory_path: Path | str,
|
|
105
116
|
create_dir_depth: int = 0,
|
|
106
117
|
) -> None:
|
|
107
118
|
self._filename_provider = filename_provider
|
|
108
|
-
self._directory_path = directory_path
|
|
119
|
+
self._directory_path = Path(directory_path)
|
|
109
120
|
self._create_dir_depth = create_dir_depth
|
|
110
121
|
|
|
111
122
|
def __call__(self, device_name: str | None = None) -> PathInfo:
|
|
@@ -119,6 +130,8 @@ class StaticPathProvider(PathProvider):
|
|
|
119
130
|
|
|
120
131
|
|
|
121
132
|
class AutoIncrementingPathProvider(PathProvider):
|
|
133
|
+
"""Provides a new numerically incremented path on each call."""
|
|
134
|
+
|
|
122
135
|
def __init__(
|
|
123
136
|
self,
|
|
124
137
|
filename_provider: FilenameProvider,
|
|
@@ -169,6 +182,8 @@ class AutoIncrementingPathProvider(PathProvider):
|
|
|
169
182
|
|
|
170
183
|
|
|
171
184
|
class YMDPathProvider(PathProvider):
|
|
185
|
+
"""Provides a path with the date included in the directory name."""
|
|
186
|
+
|
|
172
187
|
def __init__(
|
|
173
188
|
self,
|
|
174
189
|
filename_provider: FilenameProvider,
|
|
@@ -206,16 +221,20 @@ class YMDPathProvider(PathProvider):
|
|
|
206
221
|
|
|
207
222
|
|
|
208
223
|
class NameProvider(Protocol):
|
|
224
|
+
"""Base class for callable classes providing data keys."""
|
|
225
|
+
|
|
209
226
|
@abstractmethod
|
|
210
227
|
def __call__(self) -> str:
|
|
211
|
-
"""Get the name to be used as a data_key in the descriptor document"""
|
|
228
|
+
"""Get the name to be used as a data_key in the descriptor document."""
|
|
212
229
|
|
|
213
230
|
|
|
214
231
|
class DatasetDescriber(Protocol):
|
|
232
|
+
"""For describing datasets in file writing."""
|
|
233
|
+
|
|
215
234
|
@abstractmethod
|
|
216
235
|
async def np_datatype(self) -> str:
|
|
217
|
-
"""
|
|
236
|
+
"""Return the numpy datatype for this dataset."""
|
|
218
237
|
|
|
219
238
|
@abstractmethod
|
|
220
239
|
async def shape(self) -> tuple[int, ...]:
|
|
221
|
-
"""Get the shape of the data collection"""
|
|
240
|
+
"""Get the shape of the data collection."""
|
ophyd_async/core/_readable.py
CHANGED
|
@@ -17,25 +17,34 @@ from ._utils import merge_gathered_dicts
|
|
|
17
17
|
class StandardReadableFormat(Enum):
|
|
18
18
|
"""Declare how a `Device` should contribute to the `StandardReadable` verbs."""
|
|
19
19
|
|
|
20
|
-
#: Detect which verbs the child supports and contribute to:
|
|
21
|
-
#:
|
|
22
|
-
#: - ``read()``, ``describe()`` if it is `bluesky.protocols.Readable`
|
|
23
|
-
#: - ``read_configuration()``, ``describe_configuration()`` if it is
|
|
24
|
-
#: `bluesky.protocols.Configurable`
|
|
25
|
-
#: - ``stage()``, ``unstage()`` if it is `bluesky.protocols.Stageable`
|
|
26
|
-
#: - ``hints`` if it `bluesky.protocols.HasHints`
|
|
27
20
|
CHILD = "CHILD"
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
"""Detect which verbs the child supports and contribute to:
|
|
22
|
+
|
|
23
|
+
- `read()`, `describe()` if it is [](#bluesky.protocols.Readable)
|
|
24
|
+
- `read_configuration()`, `describe_configuration()` if it is
|
|
25
|
+
[](#bluesky.protocols.Configurable)
|
|
26
|
+
- `stage()`, `unstage()` if it is [](#bluesky.protocols.Stageable)
|
|
27
|
+
- `hints` if it [](#bluesky.protocols.HasHints)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
30
|
CONFIG_SIGNAL = "CONFIG_SIGNAL"
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
"""Contribute the `Signal` value to `read_configuration()` and
|
|
32
|
+
`describe_configuration()`
|
|
33
|
+
"""
|
|
34
|
+
|
|
33
35
|
HINTED_SIGNAL = "HINTED_SIGNAL"
|
|
34
|
-
|
|
36
|
+
"""Contribute the monitored `Signal` value to `read()` and `describe()` and
|
|
37
|
+
put the signal name in `hints`
|
|
38
|
+
"""
|
|
39
|
+
|
|
35
40
|
UNCACHED_SIGNAL = "UNCACHED_SIGNAL"
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
"""Contribute the uncached `Signal` value to `read()` and `describe()`
|
|
42
|
+
"""
|
|
43
|
+
|
|
38
44
|
HINTED_UNCACHED_SIGNAL = "HINTED_UNCACHED_SIGNAL"
|
|
45
|
+
"""Contribute the uncached `Signal` value to `read()` and `describe()` and
|
|
46
|
+
put the signal name in `hints`
|
|
47
|
+
"""
|
|
39
48
|
|
|
40
49
|
def __call__(self, parent: Device, child: Device):
|
|
41
50
|
if not isinstance(parent, StandardReadable):
|
|
@@ -74,11 +83,15 @@ HintedSignal.uncached = _compat_format(
|
|
|
74
83
|
class StandardReadable(
|
|
75
84
|
Device, AsyncReadable, AsyncConfigurable, AsyncStageable, HasHints
|
|
76
85
|
):
|
|
77
|
-
"""Device that
|
|
86
|
+
"""Device that provides selected child Device values in `read()`.
|
|
78
87
|
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
88
|
+
Provides the ability for children to be registered to:
|
|
89
|
+
- Participate in `stage()` and `unstage()`
|
|
90
|
+
- Provide their value in `read()` and `describe()
|
|
91
|
+
- Provide their value in `read_configuration()` and `describe_configuration()
|
|
92
|
+
- Select a value to appear in `hints`
|
|
93
|
+
|
|
94
|
+
The behavior is customized with a [](#StandardReadableFormat)
|
|
82
95
|
"""
|
|
83
96
|
|
|
84
97
|
# These must be immutable types to avoid accidental sharing between
|
|
@@ -119,7 +132,7 @@ class StandardReadable(
|
|
|
119
132
|
hints: Hints = {}
|
|
120
133
|
for new_hint in self._has_hints:
|
|
121
134
|
# Merge the existing and new hints, based on the type of the value.
|
|
122
|
-
# This avoids default dict merge
|
|
135
|
+
# This avoids default dict merge behavior that overrides the values;
|
|
123
136
|
# we want to combine them when they are Sequences, and ensure they are
|
|
124
137
|
# identical when string values.
|
|
125
138
|
for key, value in new_hint.hints.items():
|
|
@@ -156,13 +169,12 @@ class StandardReadable(
|
|
|
156
169
|
self,
|
|
157
170
|
format: StandardReadableFormat = StandardReadableFormat.CHILD,
|
|
158
171
|
) -> Generator[None, None, None]:
|
|
159
|
-
"""Context manager that calls
|
|
172
|
+
"""Context manager that calls [](#add_readables) on child Devices added within.
|
|
160
173
|
|
|
161
|
-
Scans
|
|
162
|
-
`add_readables` on any that are added with the provided
|
|
174
|
+
Scans `self.children()` on entry and exit to context manager, and calls
|
|
175
|
+
`add_readables()` on any that are added with the provided
|
|
163
176
|
`StandardReadableFormat`.
|
|
164
177
|
"""
|
|
165
|
-
|
|
166
178
|
dict_copy = dict(self.children())
|
|
167
179
|
|
|
168
180
|
yield
|
|
@@ -192,18 +204,15 @@ class StandardReadable(
|
|
|
192
204
|
Use output from the given devices to contribute to the verbs of the following
|
|
193
205
|
interfaces:
|
|
194
206
|
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
format:
|
|
205
|
-
Determines which of the devices functions are added to which verb as per the
|
|
206
|
-
`StandardReadableFormat` documentation
|
|
207
|
+
- [](#bluesky.protocols.Readable)
|
|
208
|
+
- [](#bluesky.protocols.Configurable)
|
|
209
|
+
- [](#bluesky.protocols.Stageable)
|
|
210
|
+
- [](#bluesky.protocols.HasHints)
|
|
211
|
+
|
|
212
|
+
:param devices: The devices to be added
|
|
213
|
+
:param format:
|
|
214
|
+
Determines which of the devices functions are added to which verb as
|
|
215
|
+
per the [](#StandardReadableFormat) documentation
|
|
207
216
|
"""
|
|
208
217
|
|
|
209
218
|
def assert_device_is_signalr(device: Device) -> SignalR:
|
ophyd_async/core/_settings.py
CHANGED
|
@@ -10,6 +10,28 @@ from ._signal_backend import SignalDatatypeT
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class Settings(MutableMapping[SignalRW[Any], Any], Generic[DeviceT]):
|
|
13
|
+
"""Used for supplying settings to signals.
|
|
14
|
+
|
|
15
|
+
:param device: The device that the settings are for.
|
|
16
|
+
:param settings: A dictionary of settings to start with.
|
|
17
|
+
|
|
18
|
+
:example:
|
|
19
|
+
```python
|
|
20
|
+
# Settings are created from a dict of signals to values
|
|
21
|
+
settings1 = Settings(device, {device.sig1: 1, device.sig2: 2})
|
|
22
|
+
settings2 = Settings(device, {device.sig1: 10, device.sig3: 3})
|
|
23
|
+
# They act like a dictionaries
|
|
24
|
+
assert settings1[device.sig1] == 1
|
|
25
|
+
# Including the ability to "or" two settings together
|
|
26
|
+
settings = settings1 | settings2
|
|
27
|
+
assert dict(settings) == {
|
|
28
|
+
device.sig1: 10,
|
|
29
|
+
device.sig2: 2,
|
|
30
|
+
device.sig3: 3,
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
34
|
+
|
|
13
35
|
def __init__(
|
|
14
36
|
self, device: DeviceT, settings: MutableMapping[SignalRW, Any] | None = None
|
|
15
37
|
):
|
|
@@ -48,19 +70,7 @@ class Settings(MutableMapping[SignalRW[Any], Any], Generic[DeviceT]):
|
|
|
48
70
|
return len(self._settings)
|
|
49
71
|
|
|
50
72
|
def __or__(self, other: MutableMapping[SignalRW, Any]) -> Settings[DeviceT]:
|
|
51
|
-
"""Create a new Settings that is the union of self overridden by other.
|
|
52
|
-
|
|
53
|
-
For example::
|
|
54
|
-
|
|
55
|
-
settings1 = Settings(device, {device.sig1: 1, device.sig2: 2})
|
|
56
|
-
settings2 = Settings(device, {device.sig1: 10, device.sig3: 3})
|
|
57
|
-
settings = settings1 | settings2
|
|
58
|
-
assert dict(settings) == {
|
|
59
|
-
device.sig1: 10,
|
|
60
|
-
device.sig2: 2,
|
|
61
|
-
device.sig3: 3,
|
|
62
|
-
}
|
|
63
|
-
"""
|
|
73
|
+
"""Create a new Settings that is the union of self overridden by other."""
|
|
64
74
|
if isinstance(other, Settings) and not self._is_in_device(other.device):
|
|
65
75
|
raise ValueError(f"{other.device} is not a child of {self.device}")
|
|
66
76
|
return Settings(self.device, self._settings | dict(other))
|
|
@@ -70,20 +80,19 @@ class Settings(MutableMapping[SignalRW[Any], Any], Generic[DeviceT]):
|
|
|
70
80
|
) -> tuple[Settings[DeviceT], Settings[DeviceT]]:
|
|
71
81
|
"""Partition into two Settings based on a predicate.
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
----------
|
|
75
|
-
predicate
|
|
83
|
+
:param predicate:
|
|
76
84
|
Callable that takes each signal, and returns a boolean to say if it
|
|
77
85
|
should be in the first returned Settings
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
:returns:
|
|
87
|
+
`(where_true, where_false)` where each is a Settings object.
|
|
88
|
+
The first contains the signals for which the predicate returned True,
|
|
89
|
+
and the second contains the signals for which the predicate returned False.
|
|
90
|
+
|
|
91
|
+
:example:
|
|
92
|
+
```python
|
|
93
|
+
settings = Settings(device, {device.special: 1, device.sig: 2})
|
|
94
|
+
specials, others = settings.partition(lambda sig: "special" in sig.name)
|
|
95
|
+
```
|
|
87
96
|
"""
|
|
88
97
|
where_true, where_false = Settings(self.device), Settings(self.device)
|
|
89
98
|
for signal, value in self.items():
|
|
@@ -93,12 +102,12 @@ class Settings(MutableMapping[SignalRW[Any], Any], Generic[DeviceT]):
|
|
|
93
102
|
|
|
94
103
|
|
|
95
104
|
class SettingsProvider:
|
|
105
|
+
"""Base class for providing settings."""
|
|
106
|
+
|
|
96
107
|
@abstractmethod
|
|
97
108
|
async def store(self, name: str, data: dict[str, Any]):
|
|
98
109
|
"""Store the data, associating it with the given name."""
|
|
99
|
-
...
|
|
100
110
|
|
|
101
111
|
@abstractmethod
|
|
102
112
|
async def retrieve(self, name: str) -> dict[str, Any]:
|
|
103
113
|
"""Retrieve the data associated with the given name."""
|
|
104
|
-
...
|