ophyd-async 0.9.0a1__py3-none-any.whl → 0.10.0a1__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.
Files changed (157) hide show
  1. ophyd_async/__init__.py +5 -8
  2. ophyd_async/_docs_parser.py +12 -0
  3. ophyd_async/_version.py +9 -4
  4. ophyd_async/core/__init__.py +102 -74
  5. ophyd_async/core/_derived_signal.py +271 -0
  6. ophyd_async/core/_derived_signal_backend.py +300 -0
  7. ophyd_async/core/_detector.py +158 -153
  8. ophyd_async/core/_device.py +143 -115
  9. ophyd_async/core/_device_filler.py +82 -9
  10. ophyd_async/core/_flyer.py +16 -7
  11. ophyd_async/core/_hdf_dataset.py +29 -22
  12. ophyd_async/core/_log.py +14 -23
  13. ophyd_async/core/_mock_signal_backend.py +11 -3
  14. ophyd_async/core/_protocol.py +65 -45
  15. ophyd_async/core/_providers.py +28 -9
  16. ophyd_async/core/_readable.py +74 -58
  17. ophyd_async/core/_settings.py +113 -0
  18. ophyd_async/core/_signal.py +304 -174
  19. ophyd_async/core/_signal_backend.py +60 -14
  20. ophyd_async/core/_soft_signal_backend.py +18 -12
  21. ophyd_async/core/_status.py +72 -24
  22. ophyd_async/core/_table.py +54 -17
  23. ophyd_async/core/_utils.py +101 -52
  24. ophyd_async/core/_yaml_settings.py +66 -0
  25. ophyd_async/epics/__init__.py +1 -0
  26. ophyd_async/epics/adandor/__init__.py +9 -0
  27. ophyd_async/epics/adandor/_andor.py +45 -0
  28. ophyd_async/epics/adandor/_andor_controller.py +51 -0
  29. ophyd_async/epics/adandor/_andor_io.py +34 -0
  30. ophyd_async/epics/adaravis/__init__.py +8 -1
  31. ophyd_async/epics/adaravis/_aravis.py +23 -41
  32. ophyd_async/epics/adaravis/_aravis_controller.py +23 -55
  33. ophyd_async/epics/adaravis/_aravis_io.py +13 -28
  34. ophyd_async/epics/adcore/__init__.py +36 -14
  35. ophyd_async/epics/adcore/_core_detector.py +81 -0
  36. ophyd_async/epics/adcore/_core_io.py +145 -95
  37. ophyd_async/epics/adcore/_core_logic.py +179 -88
  38. ophyd_async/epics/adcore/_core_writer.py +223 -0
  39. ophyd_async/epics/adcore/_hdf_writer.py +51 -92
  40. ophyd_async/epics/adcore/_jpeg_writer.py +26 -0
  41. ophyd_async/epics/adcore/_single_trigger.py +6 -5
  42. ophyd_async/epics/adcore/_tiff_writer.py +26 -0
  43. ophyd_async/epics/adcore/_utils.py +3 -2
  44. ophyd_async/epics/adkinetix/__init__.py +2 -1
  45. ophyd_async/epics/adkinetix/_kinetix.py +32 -27
  46. ophyd_async/epics/adkinetix/_kinetix_controller.py +11 -21
  47. ophyd_async/epics/adkinetix/_kinetix_io.py +12 -13
  48. ophyd_async/epics/adpilatus/__init__.py +7 -2
  49. ophyd_async/epics/adpilatus/_pilatus.py +28 -40
  50. ophyd_async/epics/adpilatus/_pilatus_controller.py +25 -22
  51. ophyd_async/epics/adpilatus/_pilatus_io.py +11 -9
  52. ophyd_async/epics/adsimdetector/__init__.py +8 -1
  53. ophyd_async/epics/adsimdetector/_sim.py +22 -16
  54. ophyd_async/epics/adsimdetector/_sim_controller.py +9 -43
  55. ophyd_async/epics/adsimdetector/_sim_io.py +10 -0
  56. ophyd_async/epics/advimba/__init__.py +10 -1
  57. ophyd_async/epics/advimba/_vimba.py +26 -25
  58. ophyd_async/epics/advimba/_vimba_controller.py +12 -24
  59. ophyd_async/epics/advimba/_vimba_io.py +23 -28
  60. ophyd_async/epics/core/_aioca.py +66 -30
  61. ophyd_async/epics/core/_epics_connector.py +4 -0
  62. ophyd_async/epics/core/_epics_device.py +2 -0
  63. ophyd_async/epics/core/_p4p.py +50 -18
  64. ophyd_async/epics/core/_pvi_connector.py +65 -8
  65. ophyd_async/epics/core/_signal.py +51 -51
  66. ophyd_async/epics/core/_util.py +5 -5
  67. ophyd_async/epics/demo/__init__.py +11 -49
  68. ophyd_async/epics/demo/__main__.py +31 -0
  69. ophyd_async/epics/demo/_ioc.py +32 -0
  70. ophyd_async/epics/demo/_motor.py +82 -0
  71. ophyd_async/epics/demo/_point_detector.py +42 -0
  72. ophyd_async/epics/demo/_point_detector_channel.py +22 -0
  73. ophyd_async/epics/demo/_stage.py +15 -0
  74. ophyd_async/epics/demo/{mover.db → motor.db} +2 -1
  75. ophyd_async/epics/demo/point_detector.db +59 -0
  76. ophyd_async/epics/demo/point_detector_channel.db +21 -0
  77. ophyd_async/epics/eiger/_eiger.py +1 -3
  78. ophyd_async/epics/eiger/_eiger_controller.py +11 -4
  79. ophyd_async/epics/eiger/_eiger_io.py +2 -0
  80. ophyd_async/epics/eiger/_odin_io.py +1 -2
  81. ophyd_async/epics/motor.py +83 -38
  82. ophyd_async/epics/signal.py +4 -1
  83. ophyd_async/epics/testing/__init__.py +14 -14
  84. ophyd_async/epics/testing/_example_ioc.py +68 -73
  85. ophyd_async/epics/testing/_utils.py +19 -44
  86. ophyd_async/epics/testing/test_records.db +16 -0
  87. ophyd_async/epics/testing/test_records_pva.db +17 -16
  88. ophyd_async/fastcs/__init__.py +1 -0
  89. ophyd_async/fastcs/core.py +6 -0
  90. ophyd_async/fastcs/odin/__init__.py +1 -0
  91. ophyd_async/fastcs/panda/__init__.py +8 -8
  92. ophyd_async/fastcs/panda/_block.py +29 -9
  93. ophyd_async/fastcs/panda/_control.py +12 -2
  94. ophyd_async/fastcs/panda/_hdf_panda.py +5 -1
  95. ophyd_async/fastcs/panda/_table.py +13 -7
  96. ophyd_async/fastcs/panda/_trigger.py +23 -9
  97. ophyd_async/fastcs/panda/_writer.py +27 -30
  98. ophyd_async/plan_stubs/__init__.py +16 -0
  99. ophyd_async/plan_stubs/_ensure_connected.py +12 -17
  100. ophyd_async/plan_stubs/_fly.py +3 -5
  101. ophyd_async/plan_stubs/_nd_attributes.py +9 -5
  102. ophyd_async/plan_stubs/_panda.py +14 -0
  103. ophyd_async/plan_stubs/_settings.py +152 -0
  104. ophyd_async/plan_stubs/_utils.py +3 -0
  105. ophyd_async/plan_stubs/_wait_for_awaitable.py +13 -0
  106. ophyd_async/sim/__init__.py +29 -0
  107. ophyd_async/sim/__main__.py +43 -0
  108. ophyd_async/sim/_blob_detector.py +33 -0
  109. ophyd_async/sim/_blob_detector_controller.py +48 -0
  110. ophyd_async/sim/_blob_detector_writer.py +105 -0
  111. ophyd_async/sim/_mirror_horizontal.py +46 -0
  112. ophyd_async/sim/_mirror_vertical.py +74 -0
  113. ophyd_async/sim/_motor.py +233 -0
  114. ophyd_async/sim/_pattern_generator.py +124 -0
  115. ophyd_async/sim/_point_detector.py +86 -0
  116. ophyd_async/sim/_stage.py +19 -0
  117. ophyd_async/tango/__init__.py +1 -0
  118. ophyd_async/tango/core/__init__.py +6 -1
  119. ophyd_async/tango/core/_base_device.py +41 -33
  120. ophyd_async/tango/core/_converters.py +81 -0
  121. ophyd_async/tango/core/_signal.py +21 -33
  122. ophyd_async/tango/core/_tango_readable.py +2 -19
  123. ophyd_async/tango/core/_tango_transport.py +148 -74
  124. ophyd_async/tango/core/_utils.py +47 -0
  125. ophyd_async/tango/demo/_counter.py +2 -0
  126. ophyd_async/tango/demo/_detector.py +2 -0
  127. ophyd_async/tango/demo/_mover.py +10 -6
  128. ophyd_async/tango/demo/_tango/_servers.py +4 -0
  129. ophyd_async/tango/testing/__init__.py +6 -0
  130. ophyd_async/tango/testing/_one_of_everything.py +200 -0
  131. ophyd_async/testing/__init__.py +48 -7
  132. ophyd_async/testing/__pytest_assert_rewrite.py +4 -0
  133. ophyd_async/testing/_assert.py +200 -96
  134. ophyd_async/testing/_mock_signal_utils.py +59 -73
  135. ophyd_async/testing/_one_of_everything.py +146 -0
  136. ophyd_async/testing/_single_derived.py +87 -0
  137. ophyd_async/testing/_utils.py +3 -0
  138. {ophyd_async-0.9.0a1.dist-info → ophyd_async-0.10.0a1.dist-info}/METADATA +25 -26
  139. ophyd_async-0.10.0a1.dist-info/RECORD +149 -0
  140. {ophyd_async-0.9.0a1.dist-info → ophyd_async-0.10.0a1.dist-info}/WHEEL +1 -1
  141. ophyd_async/core/_device_save_loader.py +0 -274
  142. ophyd_async/epics/demo/_mover.py +0 -95
  143. ophyd_async/epics/demo/_sensor.py +0 -37
  144. ophyd_async/epics/demo/sensor.db +0 -19
  145. ophyd_async/fastcs/panda/_utils.py +0 -16
  146. ophyd_async/sim/demo/__init__.py +0 -19
  147. ophyd_async/sim/demo/_pattern_detector/__init__.py +0 -13
  148. ophyd_async/sim/demo/_pattern_detector/_pattern_detector.py +0 -42
  149. ophyd_async/sim/demo/_pattern_detector/_pattern_detector_controller.py +0 -62
  150. ophyd_async/sim/demo/_pattern_detector/_pattern_detector_writer.py +0 -41
  151. ophyd_async/sim/demo/_pattern_detector/_pattern_generator.py +0 -207
  152. ophyd_async/sim/demo/_sim_motor.py +0 -107
  153. ophyd_async/sim/testing/__init__.py +0 -0
  154. ophyd_async-0.9.0a1.dist-info/RECORD +0 -119
  155. ophyd_async-0.9.0a1.dist-info/entry_points.txt +0 -2
  156. {ophyd_async-0.9.0a1.dist-info → ophyd_async-0.10.0a1.dist-info/licenses}/LICENSE +0 -0
  157. {ophyd_async-0.9.0a1.dist-info → ophyd_async-0.10.0a1.dist-info}/top_level.txt +0 -0
@@ -1,42 +0,0 @@
1
- from collections.abc import Sequence
2
- from pathlib import Path
3
-
4
- from ophyd_async.core import (
5
- FilenameProvider,
6
- PathProvider,
7
- SignalR,
8
- StandardDetector,
9
- StaticFilenameProvider,
10
- StaticPathProvider,
11
- )
12
-
13
- from ._pattern_detector_controller import PatternDetectorController
14
- from ._pattern_detector_writer import PatternDetectorWriter
15
- from ._pattern_generator import PatternGenerator
16
-
17
-
18
- class PatternDetector(StandardDetector):
19
- def __init__(
20
- self,
21
- path: Path,
22
- config_sigs: Sequence[SignalR] = (),
23
- name: str = "",
24
- ) -> None:
25
- fp: FilenameProvider = StaticFilenameProvider(name)
26
- self.path_provider: PathProvider = StaticPathProvider(fp, path)
27
- self.pattern_generator = PatternGenerator()
28
- writer = PatternDetectorWriter(
29
- pattern_generator=self.pattern_generator,
30
- path_provider=self.path_provider,
31
- name_provider=lambda: self.name,
32
- )
33
- controller = PatternDetectorController(
34
- pattern_generator=self.pattern_generator,
35
- path_provider=self.path_provider,
36
- )
37
- super().__init__(
38
- controller=controller,
39
- writer=writer,
40
- config_sigs=config_sigs,
41
- name=name,
42
- )
@@ -1,62 +0,0 @@
1
- import asyncio
2
-
3
- from ophyd_async.core import DetectorController, PathProvider, TriggerInfo
4
-
5
- from ._pattern_generator import PatternGenerator
6
-
7
-
8
- class PatternDetectorController(DetectorController):
9
- def __init__(
10
- self,
11
- pattern_generator: PatternGenerator,
12
- path_provider: PathProvider,
13
- exposure: float = 0.1,
14
- ) -> None:
15
- self.pattern_generator: PatternGenerator = pattern_generator
16
- self.pattern_generator.set_exposure(exposure)
17
- self.path_provider: PathProvider = path_provider
18
- self.task: asyncio.Task | None = None
19
- super().__init__()
20
-
21
- async def prepare(self, trigger_info: TriggerInfo):
22
- self._trigger_info = trigger_info
23
- if self._trigger_info.livetime is None:
24
- self._trigger_info.livetime = 0.01
25
- self.period: float = self._trigger_info.livetime + self.get_deadtime(
26
- trigger_info.livetime
27
- )
28
-
29
- async def arm(self):
30
- assert self._trigger_info.livetime
31
- assert self.period
32
- self.task = asyncio.create_task(
33
- self._coroutine_for_image_writing(
34
- self._trigger_info.livetime,
35
- self.period,
36
- self._trigger_info.total_number_of_triggers,
37
- )
38
- )
39
-
40
- async def wait_for_idle(self):
41
- if self.task:
42
- await self.task
43
-
44
- async def disarm(self):
45
- if self.task and not self.task.done():
46
- self.task.cancel()
47
- try:
48
- await self.task
49
- except asyncio.CancelledError:
50
- pass
51
- self.task = None
52
-
53
- def get_deadtime(self, exposure: float | None) -> float:
54
- return 0.001
55
-
56
- async def _coroutine_for_image_writing(
57
- self, exposure: float, period: float, frames_number: int
58
- ):
59
- for _ in range(frames_number):
60
- self.pattern_generator.set_exposure(exposure)
61
- await asyncio.sleep(period)
62
- await self.pattern_generator.write_image_to_file()
@@ -1,41 +0,0 @@
1
- from collections.abc import AsyncGenerator, AsyncIterator
2
-
3
- from event_model import DataKey
4
-
5
- from ophyd_async.core import DEFAULT_TIMEOUT, DetectorWriter, NameProvider, PathProvider
6
-
7
- from ._pattern_generator import PatternGenerator
8
-
9
-
10
- class PatternDetectorWriter(DetectorWriter):
11
- pattern_generator: PatternGenerator
12
-
13
- def __init__(
14
- self,
15
- pattern_generator: PatternGenerator,
16
- path_provider: PathProvider,
17
- name_provider: NameProvider,
18
- ) -> None:
19
- self.pattern_generator = pattern_generator
20
- self.path_provider = path_provider
21
- self.name_provider = name_provider
22
-
23
- async def open(self, multiplier: int = 1) -> dict[str, DataKey]:
24
- return await self.pattern_generator.open_file(
25
- self.path_provider, self.name_provider(), multiplier
26
- )
27
-
28
- async def close(self) -> None:
29
- self.pattern_generator.close()
30
-
31
- def collect_stream_docs(self, indices_written: int) -> AsyncIterator:
32
- return self.pattern_generator.collect_stream_docs(indices_written)
33
-
34
- async def observe_indices_written(
35
- self, timeout=DEFAULT_TIMEOUT
36
- ) -> AsyncGenerator[int, None]:
37
- async for index in self.pattern_generator.observe_indices_written(timeout):
38
- yield index
39
-
40
- async def get_indices_written(self) -> int:
41
- return self.pattern_generator.image_counter
@@ -1,207 +0,0 @@
1
- from collections.abc import AsyncGenerator, AsyncIterator
2
- from pathlib import Path
3
-
4
- import h5py
5
- import numpy as np
6
- from bluesky.protocols import StreamAsset
7
- from event_model import DataKey
8
-
9
- from ophyd_async.core import (
10
- DEFAULT_TIMEOUT,
11
- HDFDataset,
12
- HDFFile,
13
- PathProvider,
14
- observe_value,
15
- soft_signal_r_and_setter,
16
- )
17
-
18
- # raw data path
19
- DATA_PATH = "/entry/data/data"
20
-
21
- # pixel sum path
22
- SUM_PATH = "/entry/sum"
23
-
24
- MAX_UINT8_VALUE = np.iinfo(np.uint8).max
25
-
26
-
27
- def generate_gaussian_blob(height: int, width: int) -> np.ndarray:
28
- """Make a Gaussian Blob with float values in range 0..1"""
29
- x, y = np.meshgrid(np.linspace(-1, 1, width), np.linspace(-1, 1, height))
30
- d = np.sqrt(x * x + y * y)
31
- blob = np.exp(-(d**2))
32
- return blob
33
-
34
-
35
- def generate_interesting_pattern(x: float, y: float) -> float:
36
- """This function is interesting in x and y in range -10..10, returning
37
- a float value in range 0..1
38
- """
39
- z = 0.5 + (np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)) / 2
40
- return z
41
-
42
-
43
- class PatternGenerator:
44
- def __init__(
45
- self,
46
- saturation_exposure_time: float = 0.1,
47
- detector_width: int = 320,
48
- detector_height: int = 240,
49
- ) -> None:
50
- self.saturation_exposure_time = saturation_exposure_time
51
- self.exposure = saturation_exposure_time
52
- self.x = 0.0
53
- self.y = 0.0
54
- self.height = detector_height
55
- self.width = detector_width
56
- self.image_counter: int = 0
57
-
58
- # it automatically initializes to 0
59
- self.counter_signal, self._set_counter_signal = soft_signal_r_and_setter(int)
60
- self._full_intensity_blob = (
61
- generate_gaussian_blob(width=detector_width, height=detector_height)
62
- * MAX_UINT8_VALUE
63
- )
64
- self._hdf_stream_provider: HDFFile | None = None
65
- self._handle_for_h5_file: h5py.File | None = None
66
- self.target_path: Path | None = None
67
-
68
- def write_data_to_dataset(self, path: str, data_shape: tuple[int, ...], data):
69
- """Write data to named dataset, resizing to fit and flushing after."""
70
- assert self._handle_for_h5_file, "no file has been opened!"
71
- dset = self._handle_for_h5_file[path]
72
- assert isinstance(
73
- dset, h5py.Dataset
74
- ), f"Expected {path} to be dataset, got {dset}"
75
- dset.resize((self.image_counter + 1,) + data_shape)
76
- dset[self.image_counter] = data
77
- dset.flush()
78
-
79
- async def write_image_to_file(self) -> None:
80
- # generate the simulated data
81
- intensity: float = generate_interesting_pattern(self.x, self.y)
82
- detector_data = (
83
- self._full_intensity_blob
84
- * intensity
85
- * self.exposure
86
- / self.saturation_exposure_time
87
- ).astype(np.uint8)
88
-
89
- # Write the data and sum
90
- self.write_data_to_dataset(DATA_PATH, (self.height, self.width), detector_data)
91
- self.write_data_to_dataset(SUM_PATH, (), np.sum(detector_data))
92
-
93
- # counter increment is last
94
- # as only at this point the new data is visible from the outside
95
- self.image_counter += 1
96
- self._set_counter_signal(self.image_counter)
97
-
98
- def set_exposure(self, value: float) -> None:
99
- self.exposure = value
100
-
101
- def set_x(self, value: float) -> None:
102
- self.x = value
103
-
104
- def set_y(self, value: float) -> None:
105
- self.y = value
106
-
107
- async def open_file(
108
- self, path_provider: PathProvider, name: str, multiplier: int = 1
109
- ) -> dict[str, DataKey]:
110
- await self.counter_signal.connect()
111
-
112
- self.target_path = self._get_new_path(path_provider)
113
- self._path_provider = path_provider
114
-
115
- self._handle_for_h5_file = h5py.File(self.target_path, "w", libver="latest")
116
-
117
- assert self._handle_for_h5_file, "not loaded the file right"
118
-
119
- self._handle_for_h5_file.create_dataset(
120
- name=DATA_PATH,
121
- shape=(0, self.height, self.width),
122
- dtype=np.uint8,
123
- maxshape=(None, self.height, self.width),
124
- )
125
- self._handle_for_h5_file.create_dataset(
126
- name=SUM_PATH,
127
- shape=(0,),
128
- dtype=np.float64,
129
- maxshape=(None,),
130
- )
131
-
132
- # once datasets written, can switch the model to single writer multiple reader
133
- self._handle_for_h5_file.swmr_mode = True
134
- self.multiplier = multiplier
135
-
136
- outer_shape = (multiplier,) if multiplier > 1 else ()
137
-
138
- # cache state to self
139
- # Add the main data
140
- self._datasets = [
141
- HDFDataset(
142
- data_key=name,
143
- dataset=DATA_PATH,
144
- shape=(self.height, self.width),
145
- multiplier=multiplier,
146
- ),
147
- HDFDataset(
148
- f"{name}-sum",
149
- dataset=SUM_PATH,
150
- shape=(),
151
- multiplier=multiplier,
152
- ),
153
- ]
154
-
155
- describe = {
156
- ds.data_key: DataKey(
157
- source="sim://pattern-generator-hdf-file",
158
- shape=list(outer_shape) + list(ds.shape),
159
- dtype="array" if ds.shape else "number",
160
- external="STREAM:",
161
- )
162
- for ds in self._datasets
163
- }
164
- return describe
165
-
166
- def _get_new_path(self, path_provider: PathProvider) -> Path:
167
- info = path_provider(device_name="pattern")
168
- new_path: Path = info.directory_path / info.filename
169
- return new_path
170
-
171
- async def collect_stream_docs(
172
- self, indices_written: int
173
- ) -> AsyncIterator[StreamAsset]:
174
- """
175
- stream resource says "here is a dataset",
176
- stream datum says "here are N frames in that stream resource",
177
- you get one stream resource and many stream datums per scan
178
- """
179
- if self._handle_for_h5_file:
180
- self._handle_for_h5_file.flush()
181
- # when already something was written to the file
182
- if indices_written:
183
- # if no frames arrived yet, there's no file to speak of
184
- # cannot get the full filename the HDF writer will write
185
- # until the first frame comes in
186
- if not self._hdf_stream_provider:
187
- assert self.target_path, "open file has not been called"
188
- self._hdf_stream_provider = HDFFile(
189
- self.target_path,
190
- self._datasets,
191
- )
192
- for doc in self._hdf_stream_provider.stream_resources():
193
- yield "stream_resource", doc
194
- if self._hdf_stream_provider:
195
- for doc in self._hdf_stream_provider.stream_data(indices_written):
196
- yield "stream_datum", doc
197
-
198
- def close(self) -> None:
199
- if self._handle_for_h5_file:
200
- self._handle_for_h5_file.close()
201
- self._handle_for_h5_file = None
202
-
203
- async def observe_indices_written(
204
- self, timeout=DEFAULT_TIMEOUT
205
- ) -> AsyncGenerator[int, None]:
206
- async for num_captured in observe_value(self.counter_signal, timeout=timeout):
207
- yield num_captured // self.multiplier
@@ -1,107 +0,0 @@
1
- import asyncio
2
- import contextlib
3
- import time
4
-
5
- import numpy as np
6
- from bluesky.protocols import Movable, Stoppable
7
-
8
- from ophyd_async.core import (
9
- AsyncStatus,
10
- StandardReadable,
11
- WatchableAsyncStatus,
12
- WatcherUpdate,
13
- observe_value,
14
- soft_signal_r_and_setter,
15
- soft_signal_rw,
16
- )
17
- from ophyd_async.core import StandardReadableFormat as Format
18
-
19
-
20
- class SimMotor(StandardReadable, Movable, Stoppable):
21
- def __init__(self, name="", instant=True) -> None:
22
- """
23
- Simulated motor device
24
-
25
- args:
26
- - prefix: str: Signal names prefix
27
- - name: str: name of device
28
- - instant: bool: whether to move instantly, or with a delay
29
- """
30
- # Define some signals
31
- with self.add_children_as_readables(Format.HINTED_SIGNAL):
32
- self.user_readback, self._user_readback_set = soft_signal_r_and_setter(
33
- float, 0
34
- )
35
- with self.add_children_as_readables(Format.CONFIG_SIGNAL):
36
- self.velocity = soft_signal_rw(float, 0 if instant else 1.0)
37
- self.units = soft_signal_rw(str, "mm")
38
- self.user_setpoint = soft_signal_rw(float, 0)
39
-
40
- # Whether set() should complete successfully or not
41
- self._set_success = True
42
- self._move_status: AsyncStatus | None = None
43
-
44
- super().__init__(name=name)
45
-
46
- async def _move(self, old_position: float, new_position: float, move_time: float):
47
- start = time.monotonic()
48
- # Make an array of relative update times at 10Hz intervals
49
- update_times = np.arange(0.1, move_time, 0.1)
50
- # With the end position appended
51
- update_times = np.concatenate((update_times, [move_time]))
52
- # Interpolate the [old, new] position array with those update times
53
- new_positions = np.interp(
54
- update_times, [0, move_time], [old_position, new_position]
55
- )
56
- for update_time, new_position in zip(update_times, new_positions, strict=True):
57
- # Calculate how long to wait to get there
58
- relative_time = time.monotonic() - start
59
- await asyncio.sleep(update_time - relative_time)
60
- # Update the readback position
61
- self._user_readback_set(new_position)
62
-
63
- @WatchableAsyncStatus.wrap
64
- async def set(self, value: float):
65
- """
66
- Asynchronously move the motor to a new position.
67
- """
68
- new_position = value
69
- # Make sure any existing move tasks are stopped
70
- await self.stop()
71
- old_position, units, velocity = await asyncio.gather(
72
- self.user_setpoint.get_value(),
73
- self.units.get_value(),
74
- self.velocity.get_value(),
75
- )
76
- # If zero velocity, do instant move
77
- if velocity == 0:
78
- self._user_readback_set(new_position)
79
- else:
80
- move_time = abs(new_position - old_position) / velocity
81
- self._move_status = AsyncStatus(
82
- self._move(old_position, new_position, move_time)
83
- )
84
- # If stop is called then this will raise a CancelledError, ignore it
85
- with contextlib.suppress(asyncio.CancelledError):
86
- async for current_position in observe_value(
87
- self.user_readback, done_status=self._move_status
88
- ):
89
- yield WatcherUpdate(
90
- current=current_position,
91
- initial=old_position,
92
- target=new_position,
93
- name=self.name,
94
- unit=units,
95
- )
96
- if not self._set_success:
97
- raise RuntimeError("Motor was stopped")
98
-
99
- async def stop(self, success=True):
100
- """
101
- Stop the motor if it is moving
102
- """
103
- self._set_success = success
104
- if self._move_status:
105
- self._move_status.task.cancel()
106
- self._move_status = None
107
- await self.user_setpoint.set(await self.user_readback.get_value())
File without changes
@@ -1,119 +0,0 @@
1
- ophyd_async/__init__.py,sha256=tEfgj45lRItQ-_u8SRFPM-mpBh3gWvHXr3emhiJJG_M,225
2
- ophyd_async/__main__.py,sha256=n_U4O9bgm97OuboUB_9eK7eFiwy8BZSgXJ0OzbE0DqU,481
3
- ophyd_async/_version.py,sha256=fqly1zb7P_f9515NUzRb7AMheEwRLpJkaVG_Pep_nis,413
4
- ophyd_async/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- ophyd_async/core/__init__.py,sha256=GQCfHqV_nypbNkzzycqq_JxCnIIP1rwBiSB9gBq1EE0,3805
6
- ophyd_async/core/_detector.py,sha256=Zyrc5dMSmOM4bC_tOXHFfWtXnTtEQGkrAN6kydvUIFw,14307
7
- ophyd_async/core/_device.py,sha256=oIC-P6Lu6MDAdB_bHPzuT-ox8gTBAcjRNRNEh89IABk,13000
8
- ophyd_async/core/_device_filler.py,sha256=Nw-DUyuXYpvt4mmCAQaNVA0LFBBaPK84ubZo3bR39Ak,11407
9
- ophyd_async/core/_device_save_loader.py,sha256=OViN9_LWNOLuajzrHDKYEqd5I47u5npQACdGceKcIGY,8375
10
- ophyd_async/core/_flyer.py,sha256=us5z6MNGCvIfgPDTmFTxNERSP37g0WVRkRD0Z2JiMgM,1701
11
- ophyd_async/core/_hdf_dataset.py,sha256=wW_OL8OYLGOsE01ny3hGaapOrxK7BzhWTxKgz8CIXK0,2492
12
- ophyd_async/core/_log.py,sha256=UbL9AtnHVUg7r9LofzgmuKEtBESy03usCp7ejmDltG4,3679
13
- ophyd_async/core/_mock_signal_backend.py,sha256=8Upnz6QrSigeDXemjZ-jB4sV2yIPUzid-6GOfTZ-7Io,2805
14
- ophyd_async/core/_protocol.py,sha256=0pwF_EUu7LZjr-Hg6LKy6B1-5y4gpsU81JsPiNI5g_s,3317
15
- ophyd_async/core/_providers.py,sha256=ff9ZT5-PZ6rhTTdE-q8w9l_k9DuZqLWLebsKZLeJ0Ds,7112
16
- ophyd_async/core/_readable.py,sha256=7FxqxhAT1wBQqOEivgnY731zA9QoK1Tt-ZGcH7GBOXM,10623
17
- ophyd_async/core/_signal.py,sha256=KCIJongFllgRBRJxN1EjsmYR17qTu_wBm-b1OrdhT2w,20558
18
- ophyd_async/core/_signal_backend.py,sha256=YWPgLSPbfPnWIUDHvP1ArCVK8zKXJxzzbloqQe_ucCI,5040
19
- ophyd_async/core/_soft_signal_backend.py,sha256=w9zzD4eoD9SsJpORXNSaFOLJrD6biYBbCSVAybLa_7k,5926
20
- ophyd_async/core/_status.py,sha256=OUKhblRQ4KU5PDsWbpvYduM7G60JMk1NqeV4eqyPtKc,5131
21
- ophyd_async/core/_table.py,sha256=tNu396gDGjpX1xUBQXgKI7aiDugaBl2McH_kVZPn_kQ,5535
22
- ophyd_async/core/_utils.py,sha256=bzgxs1KdB35mkONzpDOg3eH6bVMIbJt49qRY0PrFqi4,9870
23
- ophyd_async/epics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- ophyd_async/epics/motor.py,sha256=d5EwfpTmblxuO1H37rzIOTDgNy1OlZmp10FWXOVUQ4o,9076
25
- ophyd_async/epics/signal.py,sha256=hJCGIIWjRVhjEHkeL1I_oPEaaN7dDFKmm7G7ZmgoTYQ,219
26
- ophyd_async/epics/adaravis/__init__.py,sha256=u979_9nQTYB0TvDOTXFN4qMrbDP8-xQFfXYMGzLVBo4,207
27
- ophyd_async/epics/adaravis/_aravis.py,sha256=XBuLQBZYj2tptY39bVzXjl6t-ZpPwqrUOwpR54l-hSo,1952
28
- ophyd_async/epics/adaravis/_aravis_controller.py,sha256=3zt-BWr-UnM1nguphHhJBNHXgBD6ntzifYXYL2o9VCM,2831
29
- ophyd_async/epics/adaravis/_aravis_io.py,sha256=_RViDrTDaTutitRbHlJ5VV23X70lvfhyY3DTzgXy6yI,1603
30
- ophyd_async/epics/adcore/__init__.py,sha256=3wMOyFGaq1X61LqK4iY4pq-m_BjhOgYZD2-mNCAjpzk,1086
31
- ophyd_async/epics/adcore/_core_io.py,sha256=4yGdsV-uivrJYas07fDFbjNwnqJukB654YneBHGsZJU,6076
32
- ophyd_async/epics/adcore/_core_logic.py,sha256=2QUWoHc6wJDwFVV81CN0rAOxhgb0SFJNLCeBxKv1Fi4,3632
33
- ophyd_async/epics/adcore/_hdf_writer.py,sha256=y0K-u3E27a8vJTklvyKrWlzRPNBp1G7DHipUtvUtOWc,7338
34
- ophyd_async/epics/adcore/_single_trigger.py,sha256=5-s0kgqqrPeNv9gjAB2pNXuxa9oEgwt9KBq58JRta6Y,1208
35
- ophyd_async/epics/adcore/_utils.py,sha256=qXOT79_CNwtO8BdpHybi4meG3Xq4pqEvWYW-Jjt_elA,3932
36
- ophyd_async/epics/adkinetix/__init__.py,sha256=cvnwOqbvEENf70eFp6bPGwayP0u14UTIhs3WiZEcF_Q,262
37
- ophyd_async/epics/adkinetix/_kinetix.py,sha256=JsQVc4d7lRCnVObJlM775hHLfp3rYRSRgOoIyRvrSek,1184
38
- ophyd_async/epics/adkinetix/_kinetix_controller.py,sha256=R5l7TaPlibeGPY67o18-Ra3i65IVIxRQ_1Zbn8kmi5s,1701
39
- ophyd_async/epics/adkinetix/_kinetix_io.py,sha256=3zqfmoTCTkhd7kiqD4wiYrnu5EADzzegaCRJFBaZuVk,910
40
- ophyd_async/epics/adpilatus/__init__.py,sha256=daimScOCCMHR2eb8VbezHOcGOkd6uIRZQiyeTQsaAx4,308
41
- ophyd_async/epics/adpilatus/_pilatus.py,sha256=hsHYeMbYJiePn3uci-YSUivQRhAaYAgicr3K145HbBA,1751
42
- ophyd_async/epics/adpilatus/_pilatus_controller.py,sha256=Bef_-2uJe8hTM-VO_xScMCnEB172n7jSmhdUevPtdJY,2676
43
- ophyd_async/epics/adpilatus/_pilatus_io.py,sha256=Jznmhwidmr_YaUdWXazWFYNQq4wn_sI1dXeo9Zhyf0M,738
44
- ophyd_async/epics/adsimdetector/__init__.py,sha256=t3crUgTEvVJGI8o6FsfN42k0A-l4v9ZBwXIYtixoE-M,128
45
- ophyd_async/epics/adsimdetector/_sim.py,sha256=jzsPJdcwdciR2mVPbvg9KhGHWWGNDQwK5TwPcS7_tco,1009
46
- ophyd_async/epics/adsimdetector/_sim_controller.py,sha256=WXKj5SclfLJ0IywCk81GmFj0ZGMkDnX7jRfatXe1EYo,1677
47
- ophyd_async/epics/advimba/__init__.py,sha256=l0ElP3Zyff_pzrTRdj9oUO9xigCfmzo3pMVjstlVsJY,320
48
- ophyd_async/epics/advimba/_vimba.py,sha256=E_RJ0uJQt-RWAY7uFTNkHaOdGYS5sa7ZbRgAe6ngXTA,1125
49
- ophyd_async/epics/advimba/_vimba_controller.py,sha256=DZNNtYeii1ogFuoW4IV8YYDdNyyt4TwcktMEr4TlJoI,2226
50
- ophyd_async/epics/advimba/_vimba_io.py,sha256=il-SZSiApx5OUQCYHUGoa0Ywu9pY01DSDvOttU15khQ,1864
51
- ophyd_async/epics/core/__init__.py,sha256=8NoQxEEc2Ny_L9nrD2fnGSf_2gJr1wCR1LwUeLNcIJo,588
52
- ophyd_async/epics/core/_aioca.py,sha256=iQWiHWYbMJLa7qeBrCz4_e16Y8A-NYYi6oYNi8oOFVY,11617
53
- ophyd_async/epics/core/_epics_connector.py,sha256=n1FlQYui8HdobPxaX3VAflrzi2UT7QCe3cFasssmVLw,1789
54
- ophyd_async/epics/core/_epics_device.py,sha256=kshNiKQhevsL2OZXa-r093L_sQGvGK_0J4PWVLg3Eqw,437
55
- ophyd_async/epics/core/_p4p.py,sha256=xtN45sJovj_5bo_e6ZUf0A_uIAeMUVgTcYJi-AtzMmw,15518
56
- ophyd_async/epics/core/_pvi_connector.py,sha256=wi9PiiWtWWE8mlHAfgDd6zKHvXn35E5DaqDvk4k5KD0,3755
57
- ophyd_async/epics/core/_signal.py,sha256=0_g2dd60tUl1inEY9hUQvWrEka4uvNW8hylrhnB76Q8,4842
58
- ophyd_async/epics/core/_util.py,sha256=wdwFd6sJoFQo3eGElPzhPaJi3KqLf5Zq_03Hoya7YsE,2079
59
- ophyd_async/epics/demo/__init__.py,sha256=wCrgemEo-zR4TTvaqCKnQ-AIUHorotV5jhftbq1tXz0,1368
60
- ophyd_async/epics/demo/_mover.py,sha256=tuAvP8TuyJtHhdSloNol7pBpiBQMcqUtGil52VjpGsE,3666
61
- ophyd_async/epics/demo/_sensor.py,sha256=VMxsjLV_V3LeLqnSqIsDHVJgpu5SmASV-rlzok_lLws,1040
62
- ophyd_async/epics/demo/mover.db,sha256=RFz0rxZue689Wh1sWTZwWeFMUrH04ttPq2u5xJH_Fp4,998
63
- ophyd_async/epics/demo/sensor.db,sha256=AstyG9E0R4KZBz2FZQSrV_QlrfLoU6M2cvYc15Lf548,553
64
- ophyd_async/epics/eiger/__init__.py,sha256=b3Tt4pVLk23Giyj50R4e94d2MxWDDmNHWhWwNq2jlaw,221
65
- ophyd_async/epics/eiger/_eiger.py,sha256=hkMsjVwrzDcE1u5BRIQtn8RSR2e0b1JMpDvuIONoNaI,1133
66
- ophyd_async/epics/eiger/_eiger_controller.py,sha256=ZJGTwSjQam15mtgG4GQ9nPNv_cA-lSLMFgTMkTK79Gg,2343
67
- ophyd_async/epics/eiger/_eiger_io.py,sha256=qTBT0SebqzlcNXtLQywSoTmAbVC2wl4i0Wn2fbcEISM,1806
68
- ophyd_async/epics/eiger/_odin_io.py,sha256=3E33ysvMlf8t0bbSVPnzUrvPgUwA7491uoViWpivpf8,4153
69
- ophyd_async/epics/testing/__init__.py,sha256=terWt7TtNaxk4dCdAGQs-7HM2Z7Vcy34eX6kcngDbi8,498
70
- ophyd_async/epics/testing/_example_ioc.py,sha256=-GC4mYacZcbLSZMmOj7Kdz08ZrGv9fsYJ4STs3n6ddQ,3481
71
- ophyd_async/epics/testing/_utils.py,sha256=-D6aKJydhM-n6290DyyKlnwCHFkbQ-j4tu5AD2JjWZ0,2443
72
- ophyd_async/epics/testing/test_records.db,sha256=25aW0vPe7ScFXI7zE83DfG6StgdrBwCEwDbfK9_hwVw,3198
73
- ophyd_async/epics/testing/test_records_pva.db,sha256=NyceNGaCZXNYaXjH2VLhvKl8Z-L6dwfE_kYZKqdIcTU,4054
74
- ophyd_async/fastcs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- ophyd_async/fastcs/core.py,sha256=MpbRLaPJwmaAuunnIV34oq1AUjT1nfv5ggtgw4I42vY,376
76
- ophyd_async/fastcs/odin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- ophyd_async/fastcs/panda/__init__.py,sha256=_o7n7ckoTM6hTRHpLphpL7r_9sADE59MRNM0gq_ut2o,980
78
- ophyd_async/fastcs/panda/_block.py,sha256=UZBWos3g4yhxGhX9oB3g_GU7jGGelgoQ2Yt2sm1MPJM,1709
79
- ophyd_async/fastcs/panda/_control.py,sha256=QIfF5y4nmjhnATeIuBTNTwXfKkNR6D9E7X0RQub0j1k,1021
80
- ophyd_async/fastcs/panda/_hdf_panda.py,sha256=UnKG8TJugDJGBm8_Grx9EtR07RtEafx1lin-JClujaQ,1172
81
- ophyd_async/fastcs/panda/_table.py,sha256=5YyAfsl3H7kxH3bDjUKHuH9DyrWQmAn9dv-v0NYzFNo,2289
82
- ophyd_async/fastcs/panda/_trigger.py,sha256=z9VGb4XPaw3xrOsvTbgpLHbduDbQJB0M4HP3w5YPB_E,3056
83
- ophyd_async/fastcs/panda/_utils.py,sha256=NdvzdKy0SOG1eCVMQo_nwRXpBo0wyi6lM5Xw3HvssOw,508
84
- ophyd_async/fastcs/panda/_writer.py,sha256=wDN6uWX1ENofmI3JBXJ7_CGooI7WsZP-JJQrRiSc6sM,6000
85
- ophyd_async/plan_stubs/__init__.py,sha256=wjpEj_BoBZJ9x2fhUPY6BzWMqyYH96JrBlJvV7frdN4,524
86
- ophyd_async/plan_stubs/_ensure_connected.py,sha256=uoqfAzghjifdfD_JM860TvMvj9T2Y12nKPvtI5l6zZc,1021
87
- ophyd_async/plan_stubs/_fly.py,sha256=ZR3oivJuMIQYXTm_QjZaCtnXY21_T8BB3dVqAnp6EHo,6208
88
- ophyd_async/plan_stubs/_nd_attributes.py,sha256=TVfy3bhnrLFBXZ6b2bREBj0LzEviEGzuGvgWK3I7tII,2198
89
- ophyd_async/sim/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
- ophyd_async/sim/demo/__init__.py,sha256=JKWFnHqmFuRRMvvU0aBuclke3OdF0iq89yvHEd4J7Bg,371
91
- ophyd_async/sim/demo/_sim_motor.py,sha256=gfvhW9TSgolAf5iAk30GviuHh680pT_RcxxTviZCzvk,3997
92
- ophyd_async/sim/demo/_pattern_detector/__init__.py,sha256=o_dSZDIl_CyS3YPSNKpGiQiR9UaC4cNzZ8_ByEN9dIk,402
93
- ophyd_async/sim/demo/_pattern_detector/_pattern_detector.py,sha256=R-UbcxHLFfCK9tBryKZN5Dit0IjYeJGP-QKV2ssKFoQ,1275
94
- ophyd_async/sim/demo/_pattern_detector/_pattern_detector_controller.py,sha256=HqlKNgjd_9pjy6pc74xdJ7JtV1Iko6cNxB2aZReJozw,1999
95
- ophyd_async/sim/demo/_pattern_detector/_pattern_detector_writer.py,sha256=nQOks4EK1Ax0Ib1pkCrmJPF8Jqr7tPusMnby-HGUnP0,1370
96
- ophyd_async/sim/demo/_pattern_detector/_pattern_generator.py,sha256=gP0Q1-1p_3KOH7mWZc5m-8OUEx_jb7SAdRXcpleRqX4,7096
97
- ophyd_async/sim/testing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
- ophyd_async/tango/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
- ophyd_async/tango/core/__init__.py,sha256=pBslTNkIt22-g-CDbG9N7pKLQVJqFe6DYXHFFYJZIo8,905
100
- ophyd_async/tango/core/_base_device.py,sha256=IN1HF1DOf9W9_FhVlzWyuU58gBFu86rYOD1vDZ_a7Wc,4717
101
- ophyd_async/tango/core/_signal.py,sha256=5ks0dyzCX66cV9R_CnmM949H1RzNQH3Q1XIUhHQCOaI,6421
102
- ophyd_async/tango/core/_tango_readable.py,sha256=c6xVH56oBp5o3C3y3PuHA5MftvmjKm20BBvrgsTO260,913
103
- ophyd_async/tango/core/_tango_transport.py,sha256=6yT-UqE7YyH6OxSisUPvwcEqf29i18jHfse6Ag4JtY0,28986
104
- ophyd_async/tango/demo/__init__.py,sha256=_j-UicTnckuIBp8PnieFMOMnLFGivnaKdmo9o0hYtzc,256
105
- ophyd_async/tango/demo/_counter.py,sha256=efBqrFj6ejzDh1aggtPXpn1iub1zB4XocRvHqBEiwcs,1105
106
- ophyd_async/tango/demo/_detector.py,sha256=0wwk7Y-Dl9QF1YsCIU_BxqI6-PQ40qN_0gknrYBkxsY,1292
107
- ophyd_async/tango/demo/_mover.py,sha256=c5whb380th1eCThs35ftW1bfNRyYRmcofg7xUp6zvV8,2837
108
- ophyd_async/tango/demo/_tango/__init__.py,sha256=FfONT7vM49nNo3a1Lv-LcMZO9EHv6bv91yY-RnxIib4,85
109
- ophyd_async/tango/demo/_tango/_servers.py,sha256=MwkkoZWJQm_cgafCBBXeQfwyAiOgU8cE90_uNfcdcGA,2916
110
- ophyd_async/testing/__init__.py,sha256=O7PFrKkVoPzhyn6f5xv6Jx6-ZahP6iBUAiqdTpalXng,706
111
- ophyd_async/testing/_assert.py,sha256=dFiy3GC_pJOTbpxvHZ3Mh357j1XtKZcuW74DlkrpJLE,3372
112
- ophyd_async/testing/_mock_signal_utils.py,sha256=VbnUQhp0QwBK4nTWirwIWRCl9pVudDj9y_qH2LhkCMc,5210
113
- ophyd_async/testing/_wait_for_pending.py,sha256=YZAR48n-CW0GsPey3zFRzMJ4byDAr3HvMIoawjmTrHw,732
114
- ophyd_async-0.9.0a1.dist-info/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
115
- ophyd_async-0.9.0a1.dist-info/METADATA,sha256=94_s1cZumUz1BuiXeodSWxW4AhoIf7Wo4tli2ddQDY0,6753
116
- ophyd_async-0.9.0a1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
117
- ophyd_async-0.9.0a1.dist-info/entry_points.txt,sha256=O0YNJTEufO0w9BozXi-JurTy2U1_o0ypeCgJLQ727Jk,58
118
- ophyd_async-0.9.0a1.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
119
- ophyd_async-0.9.0a1.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- ophyd-async = ophyd_async.__main__:main