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/__init__.py
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
"""Top level API.
|
|
2
|
-
|
|
3
|
-
.. data:: __version__
|
|
4
|
-
:type: str
|
|
5
|
-
|
|
6
|
-
Version number as calculated by https://github.com/pypa/setuptools_scm
|
|
7
|
-
"""
|
|
1
|
+
"""Top level API."""
|
|
8
2
|
|
|
9
3
|
from . import core
|
|
10
|
-
from ._version import
|
|
4
|
+
from ._version import version
|
|
5
|
+
|
|
6
|
+
__version__ = version
|
|
7
|
+
"""Version number as calculated by https://github.com/pypa/setuptools_scm"""
|
|
11
8
|
|
|
12
9
|
__all__ = ["__version__", "core"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from autodoc2.render.myst_ import MystRenderer
|
|
4
|
+
|
|
5
|
+
DOTTED_MODULE = re.compile(r"((?:[a-zA-Z_][a-zA-Z_0-9]+\.)+)")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ShortenedNamesRenderer(MystRenderer):
|
|
9
|
+
def format_annotation(self, annotation):
|
|
10
|
+
if annotation:
|
|
11
|
+
annotation = DOTTED_MODULE.sub(r"~\1", annotation)
|
|
12
|
+
return super().format_annotation(annotation)
|
ophyd_async/_version.py
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
# file generated by
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
5
|
+
|
|
3
6
|
TYPE_CHECKING = False
|
|
4
7
|
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
6
11
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
12
|
else:
|
|
8
13
|
VERSION_TUPLE = object
|
|
@@ -12,5 +17,5 @@ __version__: str
|
|
|
12
17
|
__version_tuple__: VERSION_TUPLE
|
|
13
18
|
version_tuple: VERSION_TUPLE
|
|
14
19
|
|
|
15
|
-
__version__ = version = '0.
|
|
16
|
-
__version_tuple__ = version_tuple = (0,
|
|
20
|
+
__version__ = version = '0.10.0a2'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 10, 0)
|
ophyd_async/core/__init__.py
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
"""The building blocks for making devices."""
|
|
2
|
+
|
|
3
|
+
from ._derived_signal import (
|
|
4
|
+
DerivedSignalFactory,
|
|
5
|
+
derived_signal_r,
|
|
6
|
+
derived_signal_rw,
|
|
7
|
+
derived_signal_w,
|
|
8
|
+
)
|
|
9
|
+
from ._derived_signal_backend import Transform
|
|
1
10
|
from ._detector import (
|
|
2
11
|
DetectorController,
|
|
3
|
-
DetectorControllerT,
|
|
4
12
|
DetectorTrigger,
|
|
5
13
|
DetectorWriter,
|
|
6
14
|
StandardDetector,
|
|
@@ -9,10 +17,10 @@ from ._detector import (
|
|
|
9
17
|
from ._device import Device, DeviceConnector, DeviceVector, init_devices
|
|
10
18
|
from ._device_filler import DeviceFiller
|
|
11
19
|
from ._flyer import FlyerController, StandardFlyer
|
|
12
|
-
from ._hdf_dataset import
|
|
20
|
+
from ._hdf_dataset import HDFDatasetDescription, HDFDocumentComposer
|
|
13
21
|
from ._log import config_ophyd_async_logging
|
|
14
22
|
from ._mock_signal_backend import MockSignalBackend
|
|
15
|
-
from ._protocol import AsyncConfigurable, AsyncReadable, AsyncStageable
|
|
23
|
+
from ._protocol import AsyncConfigurable, AsyncReadable, AsyncStageable, Watcher
|
|
16
24
|
from ._providers import (
|
|
17
25
|
AutoIncrementFilenameProvider,
|
|
18
26
|
AutoIncrementingPathProvider,
|
|
@@ -34,6 +42,7 @@ from ._readable import (
|
|
|
34
42
|
)
|
|
35
43
|
from ._settings import Settings, SettingsProvider
|
|
36
44
|
from ._signal import (
|
|
45
|
+
Ignore,
|
|
37
46
|
Signal,
|
|
38
47
|
SignalConnector,
|
|
39
48
|
SignalR,
|
|
@@ -47,6 +56,7 @@ from ._signal import (
|
|
|
47
56
|
soft_signal_r_and_setter,
|
|
48
57
|
soft_signal_rw,
|
|
49
58
|
wait_for_value,
|
|
59
|
+
walk_config_signals,
|
|
50
60
|
walk_rw_signals,
|
|
51
61
|
)
|
|
52
62
|
from ._signal_backend import (
|
|
@@ -55,9 +65,10 @@ from ._signal_backend import (
|
|
|
55
65
|
SignalBackend,
|
|
56
66
|
SignalDatatype,
|
|
57
67
|
SignalDatatypeT,
|
|
68
|
+
SignalMetadata,
|
|
58
69
|
make_datakey,
|
|
59
70
|
)
|
|
60
|
-
from ._soft_signal_backend import
|
|
71
|
+
from ._soft_signal_backend import SoftSignalBackend
|
|
61
72
|
from ._status import AsyncStatus, WatchableAsyncStatus, completed_status
|
|
62
73
|
from ._table import Table
|
|
63
74
|
from ._utils import (
|
|
@@ -70,8 +81,8 @@ from ._utils import (
|
|
|
70
81
|
Reference,
|
|
71
82
|
StrictEnum,
|
|
72
83
|
SubsetEnum,
|
|
73
|
-
T,
|
|
74
84
|
WatcherUpdate,
|
|
85
|
+
gather_dict,
|
|
75
86
|
get_dtype,
|
|
76
87
|
get_enum_cls,
|
|
77
88
|
get_unique,
|
|
@@ -81,84 +92,108 @@ from ._utils import (
|
|
|
81
92
|
from ._yaml_settings import YamlSettingsProvider
|
|
82
93
|
|
|
83
94
|
__all__ = [
|
|
84
|
-
|
|
85
|
-
"DetectorControllerT",
|
|
86
|
-
"DetectorTrigger",
|
|
87
|
-
"DetectorWriter",
|
|
88
|
-
"StandardDetector",
|
|
89
|
-
"TriggerInfo",
|
|
95
|
+
# Device
|
|
90
96
|
"Device",
|
|
91
97
|
"DeviceConnector",
|
|
92
|
-
"init_devices",
|
|
93
|
-
"DeviceVector",
|
|
94
98
|
"DeviceFiller",
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
"HDFFile",
|
|
99
|
-
"config_ophyd_async_logging",
|
|
100
|
-
"MockSignalBackend",
|
|
101
|
-
"AsyncConfigurable",
|
|
99
|
+
"DeviceVector",
|
|
100
|
+
"init_devices",
|
|
101
|
+
# Protocols
|
|
102
102
|
"AsyncReadable",
|
|
103
|
+
"AsyncConfigurable",
|
|
103
104
|
"AsyncStageable",
|
|
104
|
-
"
|
|
105
|
-
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
|
|
111
|
-
"StaticFilenameProvider",
|
|
112
|
-
"StaticPathProvider",
|
|
113
|
-
"UUIDFilenameProvider",
|
|
114
|
-
"YMDPathProvider",
|
|
115
|
-
"ConfigSignal",
|
|
116
|
-
"HintedSignal",
|
|
117
|
-
"StandardReadable",
|
|
118
|
-
"StandardReadableFormat",
|
|
119
|
-
"Settings",
|
|
120
|
-
"SettingsProvider",
|
|
105
|
+
"Watcher",
|
|
106
|
+
# Status
|
|
107
|
+
"AsyncStatus",
|
|
108
|
+
"WatchableAsyncStatus",
|
|
109
|
+
"WatcherUpdate",
|
|
110
|
+
"completed_status",
|
|
111
|
+
# Signal
|
|
121
112
|
"Signal",
|
|
122
|
-
"SignalConnector",
|
|
123
113
|
"SignalR",
|
|
124
|
-
"SignalRW",
|
|
125
114
|
"SignalW",
|
|
115
|
+
"SignalRW",
|
|
126
116
|
"SignalX",
|
|
127
|
-
"observe_value",
|
|
128
|
-
"observe_signals_value",
|
|
129
|
-
"set_and_wait_for_value",
|
|
130
|
-
"set_and_wait_for_other_value",
|
|
131
|
-
"soft_signal_r_and_setter",
|
|
132
|
-
"soft_signal_rw",
|
|
133
|
-
"wait_for_value",
|
|
134
|
-
"walk_rw_signals",
|
|
135
|
-
"Array1D",
|
|
136
|
-
"DTypeScalar_co",
|
|
137
117
|
"SignalBackend",
|
|
138
|
-
"
|
|
139
|
-
|
|
140
|
-
"SubsetEnum",
|
|
118
|
+
"SignalConnector",
|
|
119
|
+
# Signal Types
|
|
141
120
|
"SignalDatatype",
|
|
142
121
|
"SignalDatatypeT",
|
|
122
|
+
"DTypeScalar_co",
|
|
123
|
+
"Array1D",
|
|
124
|
+
"StrictEnum",
|
|
125
|
+
"SubsetEnum",
|
|
126
|
+
"Table",
|
|
143
127
|
"SignalMetadata",
|
|
128
|
+
# Soft signal
|
|
144
129
|
"SoftSignalBackend",
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
|
|
148
|
-
"CalculatableTimeout",
|
|
149
|
-
"Callback",
|
|
130
|
+
"soft_signal_r_and_setter",
|
|
131
|
+
"soft_signal_rw",
|
|
132
|
+
# Mock signal
|
|
150
133
|
"LazyMock",
|
|
134
|
+
"MockSignalBackend",
|
|
135
|
+
# Signal utilities
|
|
136
|
+
"observe_value",
|
|
137
|
+
"observe_signals_value",
|
|
138
|
+
"wait_for_value",
|
|
139
|
+
"set_and_wait_for_value",
|
|
140
|
+
"set_and_wait_for_other_value",
|
|
141
|
+
"walk_rw_signals",
|
|
142
|
+
"walk_config_signals",
|
|
143
|
+
# Readable
|
|
144
|
+
"StandardReadable",
|
|
145
|
+
"StandardReadableFormat",
|
|
146
|
+
# Detector
|
|
147
|
+
"StandardDetector",
|
|
148
|
+
"TriggerInfo",
|
|
149
|
+
"DetectorTrigger",
|
|
150
|
+
"DetectorController",
|
|
151
|
+
"DetectorWriter",
|
|
152
|
+
# Path
|
|
153
|
+
"PathInfo",
|
|
154
|
+
"PathProvider",
|
|
155
|
+
"StaticPathProvider",
|
|
156
|
+
"AutoIncrementingPathProvider",
|
|
157
|
+
"YMDPathProvider",
|
|
158
|
+
"FilenameProvider",
|
|
159
|
+
"StaticFilenameProvider",
|
|
160
|
+
"AutoIncrementFilenameProvider",
|
|
161
|
+
"UUIDFilenameProvider",
|
|
162
|
+
# Datatset
|
|
163
|
+
"NameProvider",
|
|
164
|
+
"DatasetDescriber",
|
|
165
|
+
"HDFDatasetDescription",
|
|
166
|
+
"HDFDocumentComposer",
|
|
167
|
+
# Flyer
|
|
168
|
+
"StandardFlyer",
|
|
169
|
+
"FlyerController",
|
|
170
|
+
# Settings
|
|
171
|
+
"Settings",
|
|
172
|
+
"SettingsProvider",
|
|
173
|
+
"YamlSettingsProvider",
|
|
174
|
+
# Utils
|
|
175
|
+
"config_ophyd_async_logging",
|
|
151
176
|
"CALCULATE_TIMEOUT",
|
|
177
|
+
"CalculatableTimeout",
|
|
178
|
+
"DEFAULT_TIMEOUT",
|
|
179
|
+
"Callback",
|
|
152
180
|
"NotConnected",
|
|
153
181
|
"Reference",
|
|
154
|
-
"
|
|
155
|
-
"T",
|
|
156
|
-
"WatcherUpdate",
|
|
182
|
+
"gather_dict",
|
|
157
183
|
"get_dtype",
|
|
158
184
|
"get_enum_cls",
|
|
159
185
|
"get_unique",
|
|
160
186
|
"in_micros",
|
|
187
|
+
"make_datakey",
|
|
161
188
|
"wait_for_connection",
|
|
162
|
-
"
|
|
163
|
-
|
|
189
|
+
"Ignore",
|
|
190
|
+
# Derived signal
|
|
191
|
+
"derived_signal_r",
|
|
192
|
+
"derived_signal_rw",
|
|
193
|
+
"derived_signal_w",
|
|
194
|
+
"Transform",
|
|
195
|
+
"DerivedSignalFactory",
|
|
196
|
+
# Back compat - delete before 1.0
|
|
197
|
+
"ConfigSignal",
|
|
198
|
+
"HintedSignal",
|
|
164
199
|
]
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
from collections.abc import Awaitable, Callable
|
|
2
|
+
from typing import Any, Generic, get_type_hints
|
|
3
|
+
|
|
4
|
+
from ._derived_signal_backend import (
|
|
5
|
+
DerivedSignalBackend,
|
|
6
|
+
SignalTransformer,
|
|
7
|
+
Transform,
|
|
8
|
+
TransformT,
|
|
9
|
+
)
|
|
10
|
+
from ._device import Device
|
|
11
|
+
from ._signal import SignalR, SignalRW, SignalT, SignalW
|
|
12
|
+
from ._signal_backend import SignalDatatypeT
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DerivedSignalFactory(Generic[TransformT]):
|
|
16
|
+
"""A factory that makes Derived Signals using a many-many Transform.
|
|
17
|
+
|
|
18
|
+
:param transform_cls:
|
|
19
|
+
The Transform subclass that will be filled in with parameters in order to
|
|
20
|
+
transform raw to derived and derived to raw.
|
|
21
|
+
:param set_derived:
|
|
22
|
+
An optional async function that takes the output of
|
|
23
|
+
`transform_cls.raw_to_derived` and applies it to the raw devices.
|
|
24
|
+
:param raw_and_transform_devices:
|
|
25
|
+
Devices whose values will be passed as parameters to the `transform_cls`,
|
|
26
|
+
and as arguments to `transform_cls.raw_to_derived`.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
transform_cls: type[TransformT],
|
|
32
|
+
set_derived: Callable[..., Awaitable[None]] | None = None,
|
|
33
|
+
**raw_and_transform_devices,
|
|
34
|
+
):
|
|
35
|
+
self._set_derived = set_derived
|
|
36
|
+
# Check the raw and transform devices match the input arguments of the Transform
|
|
37
|
+
if transform_cls is not Transform:
|
|
38
|
+
expected = list(transform_cls.model_fields) + [
|
|
39
|
+
x
|
|
40
|
+
for x in get_type_hints(transform_cls.raw_to_derived)
|
|
41
|
+
if x not in ["self", "return"]
|
|
42
|
+
]
|
|
43
|
+
if set(expected) != set(raw_and_transform_devices):
|
|
44
|
+
msg = (
|
|
45
|
+
f"Expected devices to be passed as keyword arguments {expected}, "
|
|
46
|
+
f"got {list(raw_and_transform_devices)}"
|
|
47
|
+
)
|
|
48
|
+
raise TypeError(msg)
|
|
49
|
+
set_derived_datatype = (
|
|
50
|
+
_get_first_arg_datatype(set_derived) if set_derived else None
|
|
51
|
+
)
|
|
52
|
+
self._transformer = SignalTransformer(
|
|
53
|
+
transform_cls,
|
|
54
|
+
set_derived,
|
|
55
|
+
set_derived_datatype,
|
|
56
|
+
**raw_and_transform_devices,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def _make_signal(
|
|
60
|
+
self,
|
|
61
|
+
signal_cls: type[SignalT],
|
|
62
|
+
datatype: type[SignalDatatypeT],
|
|
63
|
+
name: str,
|
|
64
|
+
units: str | None = None,
|
|
65
|
+
precision: int | None = None,
|
|
66
|
+
) -> SignalT:
|
|
67
|
+
# Check up front the raw_devices are of the right type for what the signal_cls
|
|
68
|
+
# supports
|
|
69
|
+
if issubclass(signal_cls, SignalR):
|
|
70
|
+
self._transformer.raw_and_transform_readables # noqa: B018
|
|
71
|
+
self._transformer.raw_and_transform_subscribables # noqa: B018
|
|
72
|
+
if issubclass(signal_cls, SignalW) and not self._set_derived:
|
|
73
|
+
msg = (
|
|
74
|
+
f"Must define a set_derived method to support derived "
|
|
75
|
+
f"{signal_cls.__name__}s"
|
|
76
|
+
)
|
|
77
|
+
raise ValueError(msg)
|
|
78
|
+
if issubclass(signal_cls, SignalRW):
|
|
79
|
+
self._transformer.raw_locatables # noqa: B018
|
|
80
|
+
backend = DerivedSignalBackend(
|
|
81
|
+
datatype, name, self._transformer, units, precision
|
|
82
|
+
)
|
|
83
|
+
return signal_cls(backend)
|
|
84
|
+
|
|
85
|
+
def derived_signal_r(
|
|
86
|
+
self,
|
|
87
|
+
datatype: type[SignalDatatypeT],
|
|
88
|
+
name: str,
|
|
89
|
+
units: str | None = None,
|
|
90
|
+
precision: int | None = None,
|
|
91
|
+
) -> SignalR[SignalDatatypeT]:
|
|
92
|
+
"""Create a read only derived signal.
|
|
93
|
+
|
|
94
|
+
:param datatype: The datatype of the derived signal value
|
|
95
|
+
:param name:
|
|
96
|
+
The name of the derived signal. Should be a key within the
|
|
97
|
+
return value of `transform_cls.raw_to_derived()`.
|
|
98
|
+
:param units: Engineering units for the derived signal
|
|
99
|
+
:param precision: Number of digits after the decimal place to display
|
|
100
|
+
"""
|
|
101
|
+
return self._make_signal(SignalR, datatype, name, units, precision)
|
|
102
|
+
|
|
103
|
+
def derived_signal_w(
|
|
104
|
+
self,
|
|
105
|
+
datatype: type[SignalDatatypeT],
|
|
106
|
+
name: str,
|
|
107
|
+
units: str | None = None,
|
|
108
|
+
precision: int | None = None,
|
|
109
|
+
) -> SignalW[SignalDatatypeT]:
|
|
110
|
+
"""Create a write only derived signal.
|
|
111
|
+
|
|
112
|
+
:param datatype: The datatype of the derived signal value
|
|
113
|
+
:param name:
|
|
114
|
+
The name of the derived signal. Should be a key within the
|
|
115
|
+
return value of `transform_cls.raw_to_derived()`.
|
|
116
|
+
:param units: Engineering units for the derived signal
|
|
117
|
+
:param precision: Number of digits after the decimal place to display
|
|
118
|
+
"""
|
|
119
|
+
return self._make_signal(SignalW, datatype, name, units, precision)
|
|
120
|
+
|
|
121
|
+
def derived_signal_rw(
|
|
122
|
+
self,
|
|
123
|
+
datatype: type[SignalDatatypeT],
|
|
124
|
+
name: str,
|
|
125
|
+
units: str | None = None,
|
|
126
|
+
precision: int | None = None,
|
|
127
|
+
) -> SignalRW[SignalDatatypeT]:
|
|
128
|
+
"""Create a read-write derived signal.
|
|
129
|
+
|
|
130
|
+
:param datatype: The datatype of the derived signal value
|
|
131
|
+
:param name:
|
|
132
|
+
The name of the derived signal. Should be a key within the
|
|
133
|
+
return value of `transform_cls.raw_to_derived()`.
|
|
134
|
+
:param units: Engineering units for the derived signal
|
|
135
|
+
:param precision: Number of digits after the decimal place to display
|
|
136
|
+
"""
|
|
137
|
+
return self._make_signal(SignalRW, datatype, name, units, precision)
|
|
138
|
+
|
|
139
|
+
async def transform(self) -> TransformT:
|
|
140
|
+
"""Return an instance of `transform_cls` with all the parameters filled in."""
|
|
141
|
+
return await self._transformer.get_transform()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _get_return_datatype(func: Callable[..., SignalDatatypeT]) -> type[SignalDatatypeT]:
|
|
145
|
+
args = get_type_hints(func)
|
|
146
|
+
if "return" not in args:
|
|
147
|
+
msg = f"{func} does not have a type hint for it's return value"
|
|
148
|
+
raise TypeError(msg)
|
|
149
|
+
return args["return"]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _get_first_arg_datatype(
|
|
153
|
+
func: Callable[[SignalDatatypeT], Any],
|
|
154
|
+
) -> type[SignalDatatypeT]:
|
|
155
|
+
args = get_type_hints(func)
|
|
156
|
+
args.pop("return", None)
|
|
157
|
+
if not args:
|
|
158
|
+
msg = f"{func} does not have a type hinted argument"
|
|
159
|
+
raise TypeError(msg)
|
|
160
|
+
return list(args.values())[0]
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _make_factory(
|
|
164
|
+
raw_to_derived: Callable[..., SignalDatatypeT] | None = None,
|
|
165
|
+
set_derived: Callable[[SignalDatatypeT], Awaitable[None]] | None = None,
|
|
166
|
+
raw_devices: dict[str, Device] | None = None,
|
|
167
|
+
) -> DerivedSignalFactory:
|
|
168
|
+
if raw_to_derived:
|
|
169
|
+
|
|
170
|
+
class DerivedTransform(Transform):
|
|
171
|
+
def raw_to_derived(self, **kwargs) -> dict[str, SignalDatatypeT]:
|
|
172
|
+
return {"value": raw_to_derived(**kwargs)}
|
|
173
|
+
|
|
174
|
+
# Update the signature for raw_to_derived to match what we are passed as this
|
|
175
|
+
# will be checked in DerivedSignalFactory
|
|
176
|
+
DerivedTransform.raw_to_derived.__annotations__ = get_type_hints(raw_to_derived)
|
|
177
|
+
|
|
178
|
+
return DerivedSignalFactory(
|
|
179
|
+
DerivedTransform, set_derived=set_derived, **(raw_devices or {})
|
|
180
|
+
)
|
|
181
|
+
else:
|
|
182
|
+
return DerivedSignalFactory(Transform, set_derived=set_derived)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def derived_signal_r(
|
|
186
|
+
raw_to_derived: Callable[..., SignalDatatypeT],
|
|
187
|
+
derived_units: str | None = None,
|
|
188
|
+
derived_precision: int | None = None,
|
|
189
|
+
**raw_devices: Device,
|
|
190
|
+
) -> SignalR[SignalDatatypeT]:
|
|
191
|
+
"""Create a read only derived signal.
|
|
192
|
+
|
|
193
|
+
:param raw_to_derived:
|
|
194
|
+
A function that takes the raw values as individual keyword arguments and
|
|
195
|
+
returns the derived value.
|
|
196
|
+
:param derived_units: Engineering units for the derived signal
|
|
197
|
+
:param derived_precision: Number of digits after the decimal place to display
|
|
198
|
+
:param raw_devices:
|
|
199
|
+
A dictionary of Devices to provide the values for raw_to_derived. The names
|
|
200
|
+
of these arguments must match the arguments of raw_to_derived.
|
|
201
|
+
"""
|
|
202
|
+
factory = _make_factory(raw_to_derived=raw_to_derived, raw_devices=raw_devices)
|
|
203
|
+
return factory.derived_signal_r(
|
|
204
|
+
datatype=_get_return_datatype(raw_to_derived),
|
|
205
|
+
name="value",
|
|
206
|
+
units=derived_units,
|
|
207
|
+
precision=derived_precision,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def derived_signal_rw(
|
|
212
|
+
raw_to_derived: Callable[..., SignalDatatypeT],
|
|
213
|
+
set_derived: Callable[[SignalDatatypeT], Awaitable[None]],
|
|
214
|
+
derived_units: str | None = None,
|
|
215
|
+
derived_precision: int | None = None,
|
|
216
|
+
**raw_devices: Device,
|
|
217
|
+
) -> SignalRW[SignalDatatypeT]:
|
|
218
|
+
"""Create a read-write derived signal.
|
|
219
|
+
|
|
220
|
+
:param raw_to_derived:
|
|
221
|
+
A function that takes the raw values as individual keyword arguments and
|
|
222
|
+
returns the derived value.
|
|
223
|
+
:param set_derived:
|
|
224
|
+
A function that takes the derived value and sets the raw signals. It can
|
|
225
|
+
either be an async function, or return an [](#AsyncStatus)
|
|
226
|
+
:param derived_units: Engineering units for the derived signal
|
|
227
|
+
:param derived_precision: Number of digits after the decimal place to display
|
|
228
|
+
:param raw_devices:
|
|
229
|
+
A dictionary of Devices to provide the values for raw_to_derived. The names
|
|
230
|
+
of these arguments must match the arguments of raw_to_derived.
|
|
231
|
+
"""
|
|
232
|
+
raw_to_derived_datatype = _get_return_datatype(raw_to_derived)
|
|
233
|
+
set_derived_datatype = _get_first_arg_datatype(set_derived)
|
|
234
|
+
if raw_to_derived_datatype != set_derived_datatype:
|
|
235
|
+
msg = (
|
|
236
|
+
f"{raw_to_derived} has datatype {raw_to_derived_datatype} "
|
|
237
|
+
f"!= {set_derived_datatype} dataype {set_derived_datatype}"
|
|
238
|
+
)
|
|
239
|
+
raise TypeError(msg)
|
|
240
|
+
|
|
241
|
+
factory = _make_factory(
|
|
242
|
+
raw_to_derived=raw_to_derived, set_derived=set_derived, raw_devices=raw_devices
|
|
243
|
+
)
|
|
244
|
+
return factory.derived_signal_rw(
|
|
245
|
+
datatype=raw_to_derived_datatype,
|
|
246
|
+
name="value",
|
|
247
|
+
units=derived_units,
|
|
248
|
+
precision=derived_precision,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def derived_signal_w(
|
|
253
|
+
set_derived: Callable[[SignalDatatypeT], Awaitable[None]],
|
|
254
|
+
derived_units: str | None = None,
|
|
255
|
+
derived_precision: int | None = None,
|
|
256
|
+
) -> SignalW[SignalDatatypeT]:
|
|
257
|
+
"""Create a write only derived signal.
|
|
258
|
+
|
|
259
|
+
:param set_derived:
|
|
260
|
+
A function that takes the derived value and sets the raw signals. It can
|
|
261
|
+
either be an async function, or return an [](#AsyncStatus)
|
|
262
|
+
:param derived_units: Engineering units for the derived signal
|
|
263
|
+
:param derived_precision: Number of digits after the decimal place to display
|
|
264
|
+
"""
|
|
265
|
+
factory = _make_factory(set_derived=set_derived)
|
|
266
|
+
return factory.derived_signal_w(
|
|
267
|
+
datatype=_get_first_arg_datatype(set_derived),
|
|
268
|
+
name="value",
|
|
269
|
+
units=derived_units,
|
|
270
|
+
precision=derived_precision,
|
|
271
|
+
)
|