ophyd-async 0.3.4a1__py3-none-any.whl → 0.4.0__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 (44) hide show
  1. ophyd_async/_version.py +2 -2
  2. ophyd_async/core/__init__.py +20 -8
  3. ophyd_async/core/_providers.py +186 -24
  4. ophyd_async/core/detector.py +14 -15
  5. ophyd_async/core/device.py +18 -6
  6. ophyd_async/core/signal.py +32 -8
  7. ophyd_async/core/soft_signal_backend.py +21 -6
  8. ophyd_async/epics/_backend/_aioca.py +3 -0
  9. ophyd_async/epics/_backend/_p4p.py +50 -2
  10. ophyd_async/epics/_backend/common.py +3 -1
  11. ophyd_async/epics/areadetector/aravis.py +3 -3
  12. ophyd_async/epics/areadetector/controllers/aravis_controller.py +1 -0
  13. ophyd_async/epics/areadetector/drivers/ad_base.py +3 -2
  14. ophyd_async/epics/areadetector/kinetix.py +3 -3
  15. ophyd_async/epics/areadetector/pilatus.py +3 -3
  16. ophyd_async/epics/areadetector/vimba.py +3 -3
  17. ophyd_async/epics/areadetector/writers/__init__.py +2 -2
  18. ophyd_async/epics/areadetector/writers/general_hdffile.py +97 -0
  19. ophyd_async/epics/areadetector/writers/hdf_writer.py +27 -10
  20. ophyd_async/epics/areadetector/writers/nd_file_hdf.py +3 -0
  21. ophyd_async/epics/areadetector/writers/nd_plugin.py +30 -0
  22. ophyd_async/epics/demo/demo_ad_sim_detector.py +3 -3
  23. ophyd_async/epics/motion/motor.py +132 -2
  24. ophyd_async/panda/__init__.py +15 -1
  25. ophyd_async/panda/_common_blocks.py +22 -1
  26. ophyd_async/panda/_hdf_panda.py +5 -3
  27. ophyd_async/panda/_table.py +20 -18
  28. ophyd_async/panda/_trigger.py +62 -7
  29. ophyd_async/panda/writers/_hdf_writer.py +17 -8
  30. ophyd_async/plan_stubs/ensure_connected.py +7 -2
  31. ophyd_async/plan_stubs/fly.py +58 -7
  32. ophyd_async/sim/pattern_generator.py +71 -182
  33. ophyd_async/sim/sim_pattern_detector_control.py +3 -3
  34. ophyd_async/sim/sim_pattern_detector_writer.py +9 -5
  35. ophyd_async/sim/sim_pattern_generator.py +12 -5
  36. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/METADATA +7 -2
  37. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/RECORD +41 -43
  38. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/WHEEL +1 -1
  39. ophyd_async/epics/areadetector/writers/_hdfdataset.py +0 -10
  40. ophyd_async/epics/areadetector/writers/_hdffile.py +0 -54
  41. ophyd_async/panda/writers/_panda_hdf_file.py +0 -54
  42. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/LICENSE +0 -0
  43. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/entry_points.txt +0 -0
  44. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/top_level.txt +0 -0
@@ -1,31 +1,14 @@
1
- from dataclasses import dataclass
2
1
  from pathlib import Path
3
- from typing import (
4
- Any,
5
- AsyncGenerator,
6
- AsyncIterator,
7
- Dict,
8
- Iterator,
9
- List,
10
- Optional,
11
- Sequence,
12
- )
2
+ from typing import AsyncGenerator, AsyncIterator, Dict, Optional
13
3
 
14
4
  import h5py
15
5
  import numpy as np
16
6
  from bluesky.protocols import DataKey, StreamAsset
17
- from event_model import (
18
- ComposeStreamResource,
19
- ComposeStreamResourceBundle,
20
- StreamDatum,
21
- StreamRange,
22
- StreamResource,
23
- )
24
-
25
- from ophyd_async.core import DirectoryInfo, DirectoryProvider
26
- from ophyd_async.core.mock_signal_backend import MockSignalBackend
27
- from ophyd_async.core.signal import SignalR, observe_value
7
+
8
+ from ophyd_async.core import PathProvider
9
+ from ophyd_async.core.signal import observe_value, soft_signal_r_and_setter
28
10
  from ophyd_async.core.utils import DEFAULT_TIMEOUT
11
+ from ophyd_async.epics.areadetector.writers.general_hdffile import _HDFDataset, _HDFFile
29
12
 
30
13
  # raw data path
31
14
  DATA_PATH = "/entry/data/data"
@@ -35,35 +18,6 @@ SUM_PATH = "/entry/sum"
35
18
 
36
19
  MAX_UINT8_VALUE = np.iinfo(np.uint8).max
37
20
 
38
- SLICE_NAME = "AD_HDF5_SWMR_SLICE"
39
-
40
-
41
- @dataclass
42
- class DatasetConfig:
43
- name: str
44
- shape: Sequence[int]
45
- maxshape: tuple[Any, ...] = (None,)
46
- path: Optional[str] = None
47
- multiplier: Optional[int] = 1
48
- dtype: Optional[Any] = None
49
- fillvalue: Optional[int] = None
50
-
51
-
52
- def get_full_file_description(
53
- datasets: List[DatasetConfig], outer_shape: tuple[int, ...]
54
- ):
55
- full_file_description: Dict[str, DataKey] = {}
56
- for d in datasets:
57
- source = f"soft://{d.name}"
58
- shape = outer_shape + tuple(d.shape)
59
- dtype = "number" if d.shape == [1] else "array"
60
- descriptor = DataKey(
61
- source=source, shape=shape, dtype=dtype, external="STREAM:"
62
- )
63
- key = d.name.replace("/", "_")
64
- full_file_description[key] = descriptor
65
- return full_file_description
66
-
67
21
 
68
22
  def generate_gaussian_blob(height: int, width: int) -> np.ndarray:
69
23
  """Make a Gaussian Blob with float values in range 0..1"""
@@ -81,71 +35,10 @@ def generate_interesting_pattern(x: float, y: float) -> float:
81
35
  return z
82
36
 
83
37
 
84
- class HdfStreamProvider:
85
- def __init__(
86
- self,
87
- directory_info: DirectoryInfo,
88
- full_file_name: Path,
89
- datasets: List[DatasetConfig],
90
- ) -> None:
91
- self._last_emitted = 0
92
- self._bundles: List[ComposeStreamResourceBundle] = self._compose_bundles(
93
- directory_info, full_file_name, datasets
94
- )
95
-
96
- def _compose_bundles(
97
- self,
98
- directory_info: DirectoryInfo,
99
- full_file_name: Path,
100
- datasets: List[DatasetConfig],
101
- ) -> List[StreamAsset]:
102
- path = str(full_file_name.relative_to(directory_info.root))
103
- root = str(directory_info.root)
104
- bundler_composer = ComposeStreamResource()
105
-
106
- bundles: List[ComposeStreamResourceBundle] = []
107
-
108
- bundles = [
109
- bundler_composer(
110
- spec=SLICE_NAME,
111
- root=root,
112
- resource_path=path,
113
- data_key=d.name.replace("/", "_"),
114
- resource_kwargs={
115
- "path": d.path,
116
- "multiplier": d.multiplier,
117
- "timestamps": "/entry/instrument/NDAttributes/NDArrayTimeStamp",
118
- },
119
- )
120
- for d in datasets
121
- ]
122
- return bundles
123
-
124
- def stream_resources(self) -> Iterator[StreamResource]:
125
- for bundle in self._bundles:
126
- yield bundle.stream_resource_doc
127
-
128
- def stream_data(self, indices_written: int) -> Iterator[StreamDatum]:
129
- # Indices are relative to resource
130
- if indices_written > self._last_emitted:
131
- updated_stream_range = StreamRange(
132
- start=self._last_emitted,
133
- stop=indices_written,
134
- )
135
- self._last_emitted = indices_written
136
- for bundle in self._bundles:
137
- yield bundle.compose_stream_datum(indices=updated_stream_range)
138
- return None
139
-
140
- def close(self) -> None:
141
- for bundle in self._bundles:
142
- bundle.close()
143
-
144
-
145
38
  class PatternGenerator:
146
39
  def __init__(
147
40
  self,
148
- saturation_exposure_time: float = 1,
41
+ saturation_exposure_time: float = 0.1,
149
42
  detector_width: int = 320,
150
43
  detector_height: int = 240,
151
44
  ) -> None:
@@ -155,17 +48,15 @@ class PatternGenerator:
155
48
  self.y = 0.0
156
49
  self.height = detector_height
157
50
  self.width = detector_width
158
- self.written_images_counter: int = 0
51
+ self.image_counter: int = 0
159
52
 
160
53
  # it automatically initializes to 0
161
- self.signal_backend = MockSignalBackend(int)
162
- self.mock_signal = SignalR(self.signal_backend)
163
- blob = np.array(
54
+ self.counter_signal, self._set_counter_signal = soft_signal_r_and_setter(int)
55
+ self._full_intensity_blob = (
164
56
  generate_gaussian_blob(width=detector_width, height=detector_height)
165
57
  * MAX_UINT8_VALUE
166
58
  )
167
- self.STARTING_BLOB = blob
168
- self._hdf_stream_provider: Optional[HdfStreamProvider] = None
59
+ self._hdf_stream_provider: Optional[_HDFFile] = None
169
60
  self._handle_for_h5_file: Optional[h5py.File] = None
170
61
  self.target_path: Optional[Path] = None
171
62
 
@@ -173,31 +64,24 @@ class PatternGenerator:
173
64
  assert self._handle_for_h5_file, "no file has been opened!"
174
65
  # prepare - resize the fixed hdf5 data structure
175
66
  # so that the new image can be written
176
- new_layer = self.written_images_counter + 1
177
- target_dimensions = (new_layer, self.height, self.width)
67
+ self._handle_for_h5_file[DATA_PATH].resize(
68
+ (self.image_counter + 1, self.height, self.width)
69
+ )
70
+ self._handle_for_h5_file[SUM_PATH].resize((self.image_counter + 1,))
178
71
 
179
72
  # generate the simulated data
180
73
  intensity: float = generate_interesting_pattern(self.x, self.y)
181
- detector_data: np.uint8 = np.uint8(
182
- self.STARTING_BLOB
74
+ detector_data = (
75
+ self._full_intensity_blob
183
76
  * intensity
184
77
  * self.exposure
185
78
  / self.saturation_exposure_time
186
- )
187
-
188
- self._handle_for_h5_file[DATA_PATH].resize(target_dimensions)
189
-
190
- print(f"writing image {new_layer}")
191
- assert self._handle_for_h5_file, "no file has been opened!"
192
- self._handle_for_h5_file[DATA_PATH].resize(target_dimensions)
193
-
194
- self._handle_for_h5_file[SUM_PATH].resize((new_layer,))
79
+ ).astype(np.uint8)
195
80
 
196
81
  # write data to disc (intermediate step)
197
- self._handle_for_h5_file[DATA_PATH][self.written_images_counter] = detector_data
198
- self._handle_for_h5_file[SUM_PATH][self.written_images_counter] = np.sum(
199
- detector_data
200
- )
82
+ self._handle_for_h5_file[DATA_PATH][self.image_counter] = detector_data
83
+ sum = np.sum(detector_data)
84
+ self._handle_for_h5_file[SUM_PATH][self.image_counter] = sum
201
85
 
202
86
  # save metadata - so that it's discoverable
203
87
  self._handle_for_h5_file[DATA_PATH].flush()
@@ -205,8 +89,8 @@ class PatternGenerator:
205
89
 
206
90
  # counter increment is last
207
91
  # as only at this point the new data is visible from the outside
208
- self.written_images_counter += 1
209
- await self.signal_backend.put(self.written_images_counter)
92
+ self.image_counter += 1
93
+ self._set_counter_signal(self.image_counter)
210
94
 
211
95
  def set_exposure(self, value: float) -> None:
212
96
  self.exposure = value
@@ -218,63 +102,70 @@ class PatternGenerator:
218
102
  self.y = value
219
103
 
220
104
  async def open_file(
221
- self, directory: DirectoryProvider, multiplier: int = 1
105
+ self, path_provider: PathProvider, name: str, multiplier: int = 1
222
106
  ) -> Dict[str, DataKey]:
223
- await self.mock_signal.connect()
107
+ await self.counter_signal.connect()
224
108
 
225
- self.target_path = self._get_new_path(directory)
109
+ self.target_path = self._get_new_path(path_provider)
110
+ self._path_provider = path_provider
226
111
 
227
112
  self._handle_for_h5_file = h5py.File(self.target_path, "w", libver="latest")
228
113
 
229
114
  assert self._handle_for_h5_file, "not loaded the file right"
230
115
 
231
- datasets = self._get_datasets()
232
- for d in datasets:
233
- self._handle_for_h5_file.create_dataset(
234
- name=d.name,
235
- shape=d.shape,
236
- dtype=d.dtype,
237
- maxshape=d.maxshape,
238
- )
116
+ self._handle_for_h5_file.create_dataset(
117
+ name=DATA_PATH,
118
+ shape=(0, self.height, self.width),
119
+ dtype=np.uint8,
120
+ maxshape=(None, self.height, self.width),
121
+ )
122
+ self._handle_for_h5_file.create_dataset(
123
+ name=SUM_PATH,
124
+ shape=(0,),
125
+ dtype=np.float64,
126
+ maxshape=(None,),
127
+ )
239
128
 
240
129
  # once datasets written, can switch the model to single writer multiple reader
241
130
  self._handle_for_h5_file.swmr_mode = True
131
+ self.multiplier = multiplier
242
132
 
243
133
  outer_shape = (multiplier,) if multiplier > 1 else ()
244
- full_file_description = get_full_file_description(datasets, outer_shape)
245
134
 
246
135
  # cache state to self
247
- self._datasets = datasets
248
- self.multiplier = multiplier
249
- self._directory_provider = directory
250
- return full_file_description
136
+ # Add the main data
137
+ self._datasets = [
138
+ _HDFDataset(
139
+ data_key=name,
140
+ dataset=DATA_PATH,
141
+ shape=(self.height, self.width),
142
+ multiplier=multiplier,
143
+ ),
144
+ _HDFDataset(
145
+ f"{name}-sum",
146
+ dataset=SUM_PATH,
147
+ shape=(),
148
+ multiplier=multiplier,
149
+ ),
150
+ ]
151
+
152
+ describe = {
153
+ ds.data_key: DataKey(
154
+ source="sim://pattern-generator-hdf-file",
155
+ shape=outer_shape + tuple(ds.shape),
156
+ dtype="array" if ds.shape else "number",
157
+ external="STREAM:",
158
+ )
159
+ for ds in self._datasets
160
+ }
161
+ return describe
251
162
 
252
- def _get_new_path(self, directory: DirectoryProvider) -> Path:
253
- info = directory()
254
- filename = f"{info.prefix}pattern{info.suffix}.h5"
163
+ def _get_new_path(self, path_provider: PathProvider) -> Path:
164
+ info = path_provider(device_name="pattern")
165
+ filename = info.filename
255
166
  new_path: Path = info.root / info.resource_dir / filename
256
167
  return new_path
257
168
 
258
- def _get_datasets(self) -> List[DatasetConfig]:
259
- raw_dataset = DatasetConfig(
260
- # name=data_name,
261
- name=DATA_PATH,
262
- dtype=np.uint8,
263
- shape=(1, self.height, self.width),
264
- maxshape=(None, self.height, self.width),
265
- )
266
-
267
- sum_dataset = DatasetConfig(
268
- name=SUM_PATH,
269
- dtype=np.float64,
270
- shape=(1,),
271
- maxshape=(None,),
272
- fillvalue=-1,
273
- )
274
-
275
- datasets: List[DatasetConfig] = [raw_dataset, sum_dataset]
276
- return datasets
277
-
278
169
  async def collect_stream_docs(
279
170
  self, indices_written: int
280
171
  ) -> AsyncIterator[StreamAsset]:
@@ -292,10 +183,8 @@ class PatternGenerator:
292
183
  # until the first frame comes in
293
184
  if not self._hdf_stream_provider:
294
185
  assert self.target_path, "open file has not been called"
295
- datasets = self._get_datasets()
296
- self._datasets = datasets
297
- self._hdf_stream_provider = HdfStreamProvider(
298
- self._directory_provider(),
186
+ self._hdf_stream_provider = _HDFFile(
187
+ self._path_provider(),
299
188
  self.target_path,
300
189
  self._datasets,
301
190
  )
@@ -314,5 +203,5 @@ class PatternGenerator:
314
203
  async def observe_indices_written(
315
204
  self, timeout=DEFAULT_TIMEOUT
316
205
  ) -> AsyncGenerator[int, None]:
317
- async for num_captured in observe_value(self.mock_signal, timeout=timeout):
206
+ async for num_captured in observe_value(self.counter_signal, timeout=timeout):
318
207
  yield num_captured // self.multiplier
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  from typing import Optional
3
3
 
4
- from ophyd_async.core import DirectoryProvider
4
+ from ophyd_async.core import PathProvider
5
5
  from ophyd_async.core.async_status import AsyncStatus
6
6
  from ophyd_async.core.detector import DetectorControl, DetectorTrigger
7
7
  from ophyd_async.sim.pattern_generator import PatternGenerator
@@ -11,12 +11,12 @@ class SimPatternDetectorControl(DetectorControl):
11
11
  def __init__(
12
12
  self,
13
13
  pattern_generator: PatternGenerator,
14
- directory_provider: DirectoryProvider,
14
+ path_provider: PathProvider,
15
15
  exposure: float = 0.1,
16
16
  ) -> None:
17
17
  self.pattern_generator: PatternGenerator = pattern_generator
18
18
  self.pattern_generator.set_exposure(exposure)
19
- self.directory_provider: DirectoryProvider = directory_provider
19
+ self.path_provider: PathProvider = path_provider
20
20
  self.task: Optional[asyncio.Task] = None
21
21
  super().__init__()
22
22
 
@@ -2,7 +2,7 @@ from typing import AsyncGenerator, AsyncIterator, Dict
2
2
 
3
3
  from bluesky.protocols import DataKey
4
4
 
5
- from ophyd_async.core import DirectoryProvider
5
+ from ophyd_async.core import NameProvider, PathProvider
6
6
  from ophyd_async.core.detector import DetectorWriter
7
7
  from ophyd_async.sim.pattern_generator import PatternGenerator
8
8
 
@@ -11,14 +11,18 @@ class SimPatternDetectorWriter(DetectorWriter):
11
11
  pattern_generator: PatternGenerator
12
12
 
13
13
  def __init__(
14
- self, pattern_generator: PatternGenerator, directoryProvider: DirectoryProvider
14
+ self,
15
+ pattern_generator: PatternGenerator,
16
+ path_provider: PathProvider,
17
+ name_provider: NameProvider,
15
18
  ) -> None:
16
19
  self.pattern_generator = pattern_generator
17
- self.directory_provider = directoryProvider
20
+ self.path_provider = path_provider
21
+ self.name_provider = name_provider
18
22
 
19
23
  async def open(self, multiplier: int = 1) -> Dict[str, DataKey]:
20
24
  return await self.pattern_generator.open_file(
21
- self.directory_provider, multiplier
25
+ self.path_provider, self.name_provider(), multiplier
22
26
  )
23
27
 
24
28
  async def close(self) -> None:
@@ -31,4 +35,4 @@ class SimPatternDetectorWriter(DetectorWriter):
31
35
  return self.pattern_generator.observe_indices_written()
32
36
 
33
37
  async def get_indices_written(self) -> int:
34
- return self.pattern_generator.written_images_counter
38
+ return self.pattern_generator.image_counter
@@ -1,7 +1,12 @@
1
1
  from pathlib import Path
2
2
  from typing import Sequence
3
3
 
4
- from ophyd_async.core import DirectoryProvider, StaticDirectoryProvider
4
+ from ophyd_async.core import (
5
+ FilenameProvider,
6
+ PathProvider,
7
+ StaticFilenameProvider,
8
+ StaticPathProvider,
9
+ )
5
10
  from ophyd_async.core.detector import StandardDetector
6
11
  from ophyd_async.protocols import AsyncReadable
7
12
  from ophyd_async.sim.pattern_generator import PatternGenerator
@@ -15,17 +20,19 @@ class SimPatternDetector(StandardDetector):
15
20
  self,
16
21
  path: Path,
17
22
  config_sigs: Sequence[AsyncReadable] = [],
18
- name: str = "sim_pattern_detector",
23
+ name: str = "",
19
24
  ) -> None:
20
- self.directory_provider: DirectoryProvider = StaticDirectoryProvider(path)
25
+ fp: FilenameProvider = StaticFilenameProvider(name)
26
+ self.path_provider: PathProvider = StaticPathProvider(fp, path)
21
27
  self.pattern_generator = PatternGenerator()
22
28
  writer = SimPatternDetectorWriter(
23
29
  pattern_generator=self.pattern_generator,
24
- directoryProvider=self.directory_provider,
30
+ path_provider=self.path_provider,
31
+ name_provider=lambda: self.name,
25
32
  )
26
33
  controller = SimPatternDetectorControl(
27
34
  pattern_generator=self.pattern_generator,
28
- directory_provider=self.directory_provider,
35
+ path_provider=self.path_provider,
29
36
  )
30
37
  super().__init__(
31
38
  controller=controller,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ophyd-async
3
- Version: 0.3.4a1
3
+ Version: 0.4.0
4
4
  Summary: Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
5
5
  Author-email: Tom Cobb <tom.cobb@diamond.ac.uk>
6
6
  License: BSD 3-Clause License
@@ -45,10 +45,12 @@ Requires-Dist: numpy <2.0.0
45
45
  Requires-Dist: packaging
46
46
  Requires-Dist: pint
47
47
  Requires-Dist: bluesky >=1.13.0a3
48
- Requires-Dist: event-model <1.21.0
48
+ Requires-Dist: event-model
49
49
  Requires-Dist: p4p
50
50
  Requires-Dist: pyyaml
51
51
  Requires-Dist: colorlog
52
+ Requires-Dist: pydantic >=2.0
53
+ Requires-Dist: pydantic-numpy
52
54
  Provides-Extra: ca
53
55
  Requires-Dist: aioca >=1.6 ; extra == 'ca'
54
56
  Provides-Extra: dev
@@ -79,10 +81,13 @@ Requires-Dist: pytest-faulthandler ; extra == 'dev'
79
81
  Requires-Dist: pytest-rerunfailures ; extra == 'dev'
80
82
  Requires-Dist: pytest-timeout ; extra == 'dev'
81
83
  Requires-Dist: ruff ; extra == 'dev'
84
+ Requires-Dist: sphinx <7.4.0 ; extra == 'dev'
82
85
  Requires-Dist: sphinx-autobuild ; extra == 'dev'
86
+ Requires-Dist: autodoc-pydantic ; extra == 'dev'
83
87
  Requires-Dist: sphinxcontrib-mermaid ; extra == 'dev'
84
88
  Requires-Dist: sphinx-copybutton ; extra == 'dev'
85
89
  Requires-Dist: sphinx-design ; extra == 'dev'
90
+ Requires-Dist: super-state-machine ; extra == 'dev'
86
91
  Requires-Dist: tox-direct ; extra == 'dev'
87
92
  Requires-Dist: types-mock ; extra == 'dev'
88
93
  Requires-Dist: types-pyyaml ; extra == 'dev'
@@ -1,86 +1,84 @@
1
1
  ophyd_async/__init__.py,sha256=v-rRiDOgZ3sQSMQKq0vgUQZvpeOkoHFXissAx6Ktg84,61
2
2
  ophyd_async/__main__.py,sha256=G-Zcv_G9zK7Nhx6o5L5w-wyhMxdl_WgyMELu8IMFqAE,328
3
- ophyd_async/_version.py,sha256=GeD2BgjHboEmcr7_O2gtjDoE83JU6uGSFLE7dAp8RDQ,413
3
+ ophyd_async/_version.py,sha256=j90u3VVU4UrJf1fgMUhaZarHK_Do2XGYXr-vZvOFzVo,411
4
4
  ophyd_async/log.py,sha256=DbMjt0bkfUOLHIinZYt0Q0FHZmCXXi5x8y0uFiEmqoQ,3587
5
5
  ophyd_async/protocols.py,sha256=EF2W9nfElV-0QNMYrX1zusL1PqDJR3kNsjlalR29j0I,3412
6
- ophyd_async/core/__init__.py,sha256=xqO9riU_uKqGAOi0ty0cbcI4Oawi_J3XTYLtwNSXGOE,3061
7
- ophyd_async/core/_providers.py,sha256=LrlTMPHKXWOPVkpAOw-pqBq0kip-c3C9ZZPoFfiaV4M,2212
6
+ ophyd_async/core/__init__.py,sha256=smUUnG2xf5XJMTk_aGKAPg2ZEZTWhABd-p4qCExipqY,3366
7
+ ophyd_async/core/_providers.py,sha256=-HlisysZZcqs6z1yQsWCpof7hQ9QTbg2IYpm4XaErGQ,7454
8
8
  ophyd_async/core/async_status.py,sha256=9TOgOXIAuH62RDo5t-Y5GdjrJ76d_6TFlBxYv-5_a88,4367
9
- ophyd_async/core/detector.py,sha256=NMX8y_yiViHbv3CaJ7LxzXYkH6tCWI3LocpQ3w4lGEQ,11176
10
- ophyd_async/core/device.py,sha256=280zFnLCoiMZAA-Dh1_AjUSnhxUfKYGgj4H_2S1njOA,7086
9
+ ophyd_async/core/detector.py,sha256=x6zxmDjbh8d6meJc8L2NidxI3Uj5bFPWo_FSaRDDBoM,11271
10
+ ophyd_async/core/device.py,sha256=mb-zxxmr5RftdBO8YPDJayP4ovNWEgW4qh2v1UU7ROg,7553
11
11
  ophyd_async/core/device_save_loader.py,sha256=EK7FB5oWiLI_s2KZ1BNDQ2AUKVbFLlimMl0vXfsjcgo,8223
12
12
  ophyd_async/core/flyer.py,sha256=bIjzBkrl8HVAlKgsZ_FF0WL69Qvksyzp9ZWmTLl8Yrw,2304
13
13
  ophyd_async/core/mock_signal_backend.py,sha256=Ug6jK72wm9vM6EueoUrYgcXtiFzdPUEISRe86LdyYKc,2844
14
14
  ophyd_async/core/mock_signal_utils.py,sha256=LE8VxNq3jfaTePnHHpZpKCi1vwKi8EIg-g1jfw-Q5bQ,4726
15
- ophyd_async/core/signal.py,sha256=hPpMcdq7zx6HOkyQCJrMD5F3uLBEJJTfwL6DsbcTELo,17601
15
+ ophyd_async/core/signal.py,sha256=9zRoHLkSHoa451LmABtpzSvymo0GmC3jAQDQDp0kuMU,18531
16
16
  ophyd_async/core/signal_backend.py,sha256=U9J6jzHXRNIrdtGiZBVxXTRtzeejXiXEEIOGRIQhiS8,2678
17
- ophyd_async/core/soft_signal_backend.py,sha256=6ve1NWuEZFW4oFkAdSfTKFg06fv7rDLgr5IAEr_axeo,6262
17
+ ophyd_async/core/soft_signal_backend.py,sha256=96Zk8ly8Qw6_l4RmB7NW95fbFCsRUTXH2H2JtH46_pY,6688
18
18
  ophyd_async/core/standard_readable.py,sha256=fhq_WAZtLYWrw6DvvrFRYRAPOUP2_IcX4qLucoEEeOg,9049
19
19
  ophyd_async/core/utils.py,sha256=3oZcXNqAUHX4ZWMBH5gSuK6cFWEhSkZ9GSDYv0pf8jc,5783
20
20
  ophyd_async/epics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  ophyd_async/epics/_backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- ophyd_async/epics/_backend/_aioca.py,sha256=YsKHGaHtYjBte5Tz-AftTENaeV6UGRnonX-1UmAQGqg,11319
23
- ophyd_async/epics/_backend/_p4p.py,sha256=oCT8MeVWlhmsxZ8YRSrelrY8W3NvfpXcMlfAKL_AUNY,14331
24
- ophyd_async/epics/_backend/common.py,sha256=ffdcKhtUc8Mmm0AsV0K7cUoOttF6avcN6Kdd4QHjrSw,1833
22
+ ophyd_async/epics/_backend/_aioca.py,sha256=JwMX_8E1kw8GWlIRhXpJ2BExbZG7Ps2OOQWgdqwzo8c,11433
23
+ ophyd_async/epics/_backend/_p4p.py,sha256=RN3skNzG9PKKvIUccqnccVvsfgm4lS1x4g02X5ds00c,15816
24
+ ophyd_async/epics/_backend/common.py,sha256=gxI3c0T_Y-TVnAPabzPF0Y5Xo12xSvtpp5ytAfCxwWA,1863
25
25
  ophyd_async/epics/areadetector/__init__.py,sha256=ViKzx-wUxkRyNR33wfpL11QB97o0J47_KMyI2C_NphI,510
26
- ophyd_async/epics/areadetector/aravis.py,sha256=YklN4V0loqUQBs4swVX304N49JIGPvrNOk8iA5EWofg,2127
27
- ophyd_async/epics/areadetector/kinetix.py,sha256=7rE2MLnz9DEmeiN9pCekDfpXuZ2DErnMajRp_9eoLZY,1359
28
- ophyd_async/epics/areadetector/pilatus.py,sha256=hs3v8QUIwTHNg7i1mRSg9SbIIsoUZg90OxJ740gEKpo,2044
26
+ ophyd_async/epics/areadetector/aravis.py,sha256=zRhC0tQTZvBUUcPqJV9EZFJhCL_4ib-O8VcSbPxf9wg,2107
27
+ ophyd_async/epics/areadetector/kinetix.py,sha256=lO-vuE_joIklLL2f0isUZCwVyhFcb4HkXqeCa-gD4kQ,1339
28
+ ophyd_async/epics/areadetector/pilatus.py,sha256=u-c_imklak1GQObqvQ-ziiS3_GEHP5csPlsVfaM_sDU,2024
29
29
  ophyd_async/epics/areadetector/single_trigger_det.py,sha256=U92dqhioIfnve3jtCThq9gXBCdEzzqzY4ezk6rZV19g,1182
30
30
  ophyd_async/epics/areadetector/utils.py,sha256=p66UbVdKRFj6Sm1Qvm23kmlVyBMMqIvXFxA3x17YnSk,2824
31
- ophyd_async/epics/areadetector/vimba.py,sha256=IxG8KLzfb84iLtzf6ZoX9JikqZLP49lwkWu33bkDV9Y,1291
31
+ ophyd_async/epics/areadetector/vimba.py,sha256=9KkgXJjJJHc0QQ7E4FAt6n7d6-leUAnEgLVzrIoLE6c,1271
32
32
  ophyd_async/epics/areadetector/controllers/__init__.py,sha256=af58ci7X2z2s_FyUwR3IGQrws8q4TKcBw7vFyIS5FoI,217
33
33
  ophyd_async/epics/areadetector/controllers/ad_sim_controller.py,sha256=mthZ6WxajMEgUKptq3bnkIctbLhjzTagV66i1auB8cg,1587
34
- ophyd_async/epics/areadetector/controllers/aravis_controller.py,sha256=CIfnZdq_NobO_UMC2TJoAfUEP9GlzZg5z5bz6Dn1DxY,2669
34
+ ophyd_async/epics/areadetector/controllers/aravis_controller.py,sha256=2C3pGdvzVDBlYsJv4USv-hZ-BpyQUxoZqJTKz0_zPLY,2707
35
35
  ophyd_async/epics/areadetector/controllers/kinetix_controller.py,sha256=9QmydX85QOXfQL_UX49M9EQ2b2hUZPVzLxgGQn-A9Oc,1611
36
36
  ophyd_async/epics/areadetector/controllers/pilatus_controller.py,sha256=6AiMz2yBA9xig-BrAIAc9CDxwM4Cjfebc4dd7QRutB0,2740
37
37
  ophyd_async/epics/areadetector/controllers/vimba_controller.py,sha256=Eh4Hr9rWgq1mKvE93JzgixntjPHxF3_07GTFqiOdZqE,2123
38
38
  ophyd_async/epics/areadetector/drivers/__init__.py,sha256=X-KdXw7YWNXpaUCXby2Spqvho2x2n72OavR-3mRlxzk,605
39
- ophyd_async/epics/areadetector/drivers/ad_base.py,sha256=OMySyCE9dcFRcVLC5Q0wUkri3QtRljIbn4KFdkumI4M,4553
39
+ ophyd_async/epics/areadetector/drivers/ad_base.py,sha256=AB1exQsxL_207Uz88GapYqkWblODqTumaaW2CPLYLV4,4583
40
40
  ophyd_async/epics/areadetector/drivers/aravis_driver.py,sha256=K1if0Nv1ZNEvcOha6NVYA9t9VqsBNxKCmbajlysGF2Q,1491
41
41
  ophyd_async/epics/areadetector/drivers/kinetix_driver.py,sha256=yIV23BkGBJ4i0VskLiLL7AFbadCCR6Ch1UwUDJ9r2YM,743
42
42
  ophyd_async/epics/areadetector/drivers/pilatus_driver.py,sha256=0DBBuiR_FtwzVVdDW0ifdSrdKZtnprWuy87g66o8RlQ,619
43
43
  ophyd_async/epics/areadetector/drivers/vimba_driver.py,sha256=J54VtWkOklfbSqZYxGWH1e6Uzm9_Gph_ZbCf9Zax0LU,1713
44
- ophyd_async/epics/areadetector/writers/__init__.py,sha256=tpPcrYd1hs8WS7C0gmCnR2EBwjE5RzCljI7WwZ2V_LM,191
45
- ophyd_async/epics/areadetector/writers/_hdfdataset.py,sha256=E0C9VgsPyY35h7k0mvcIhjsIVNavApLxizqNWlM388w,167
46
- ophyd_async/epics/areadetector/writers/_hdffile.py,sha256=YtUgOKX53m0TaFEGBW671qXqNuuEKxEyLV5Ein1fjvo,1799
47
- ophyd_async/epics/areadetector/writers/hdf_writer.py,sha256=ZpbVilNVv81OpbCrqaeZUoHLarrjzRWEGe-zI1Wxyyw,5436
48
- ophyd_async/epics/areadetector/writers/nd_file_hdf.py,sha256=EkiaEh_0U6Iz17jFi2IIsRPsVQTQIJRG8EPNCiAHkkU,1762
49
- ophyd_async/epics/areadetector/writers/nd_plugin.py,sha256=GUzaeTMdG07Rb1x0WzBBxMEltBhr10jb5dL29tEWXEQ,1547
44
+ ophyd_async/epics/areadetector/writers/__init__.py,sha256=bzUzlEYa3eIKWnT-uVXPiRDdxH1OAzCJCRLJJBF37QA,225
45
+ ophyd_async/epics/areadetector/writers/general_hdffile.py,sha256=aFS_qXC99cUVWPPxgeqgxeF89IinJhtNVQIZ3C5K-C4,2608
46
+ ophyd_async/epics/areadetector/writers/hdf_writer.py,sha256=GzvaXSzRSLjGktGh4ihfkB1Vpv69g8PCMN0h1RqSv08,5940
47
+ ophyd_async/epics/areadetector/writers/nd_file_hdf.py,sha256=fMj_rGV5PX4VlayGzWvyEkFIPM2Mj9w5MEADA3yxSrw,1983
48
+ ophyd_async/epics/areadetector/writers/nd_plugin.py,sha256=OR2-UFypfBW-lLTrVD1_FFbWK-tl863cOxCrH06x7FA,2393
50
49
  ophyd_async/epics/demo/__init__.py,sha256=ZcuZ66aIQ58WSydLOSKnk-h_W-aWjhDRZkWQA6f3sig,5790
51
- ophyd_async/epics/demo/demo_ad_sim_detector.py,sha256=06y65yvaqXvL2rDocjYyLz9kTVzuwV-LeuPhEfExdOA,944
50
+ ophyd_async/epics/demo/demo_ad_sim_detector.py,sha256=x7aD2shaHBvYHP_PTSutXi9Yep8lvOMqeNHxMT7ZGY0,924
52
51
  ophyd_async/epics/demo/mover.db,sha256=RFz0rxZue689Wh1sWTZwWeFMUrH04ttPq2u5xJH_Fp4,998
53
52
  ophyd_async/epics/demo/sensor.db,sha256=AVtiydrdtwAz2EFurO2Ult9SSRtre3r0akOBbL98LT0,554
54
53
  ophyd_async/epics/motion/__init__.py,sha256=tnmVRIwKa9PdN_xonJdAUD04UpEceh-hoD7XI62yDB0,46
55
- ophyd_async/epics/motion/motor.py,sha256=tqLV4TaW2MIapZsmx4wxnGOdKfkhxKLUPbTHA4YLdYE,3514
54
+ ophyd_async/epics/motion/motor.py,sha256=GrlIgyCK45nfVFw7gRccdt4qy8jXWdcbBzcp6MD3OY4,8466
56
55
  ophyd_async/epics/pvi/__init__.py,sha256=TbOQNY4enQWgtr1T7x129vpo2p7FIFlr8cyZqqv5Lk4,158
57
56
  ophyd_async/epics/pvi/pvi.py,sha256=Kc3klnA9F82h_p2atFYXe-wFO9OzN5TV69Tc56tD2do,12204
58
57
  ophyd_async/epics/signal/__init__.py,sha256=JXKBSGpRL9y3auh27JRxsqDn_rBOXpJjtd4nCuDOX2g,261
59
58
  ophyd_async/epics/signal/_epics_transport.py,sha256=DEIL0iYUAWssysVEgWGu1fHSM1l-ATV2kjUgPtDN9LY,858
60
59
  ophyd_async/epics/signal/signal.py,sha256=M8ZVG_zLdYJfroCRX-u_w8c3yIhswSRw8e3RkW2szio,3166
61
- ophyd_async/panda/__init__.py,sha256=FuSnvp-RtdA0X4RcHEF0nTiXymRts2MNdFmF_1_i41w,775
62
- ophyd_async/panda/_common_blocks.py,sha256=OrA_mSJslxuhjIAD8Liye1-1yTl3DihqFDBXvJGlPFs,1088
63
- ophyd_async/panda/_hdf_panda.py,sha256=LWWQErG_cxM7zWqKG8c40O55ZpfTu3F70d4jVvRaeMo,1308
60
+ ophyd_async/panda/__init__.py,sha256=RjEow4N-rgEPEZdlsDZElUv-VsLGRX3Awoo4Zij_mIQ,1058
61
+ ophyd_async/panda/_common_blocks.py,sha256=fl8rGfAAslgN7kIzQhbqQkRXVlWvKT6nqiYEE_30Ono,1601
62
+ ophyd_async/panda/_hdf_panda.py,sha256=TU0xa3wLd5zaf_GRBwDFjYirpHAyIRRZ-V8JxHyaLuY,1350
64
63
  ophyd_async/panda/_panda_controller.py,sha256=dIqcjmaIHVrki8UXSoDx46kk6I2Lhpe2o3sXNg5f-RQ,1238
65
- ophyd_async/panda/_table.py,sha256=keCGT66y91feO_MD3a6aMsgx27JuLYWLrAkl0lRXUKY,5854
66
- ophyd_async/panda/_trigger.py,sha256=tBH8uq_4o1ASG9yofVxq3tjf5v8LPzniDTRL4yjramI,1195
64
+ ophyd_async/panda/_table.py,sha256=atd9wiam0XQH89doqzn0U6J42CFQBKDs9K1_q5GcJR8,6093
65
+ ophyd_async/panda/_trigger.py,sha256=6G30e--M9OGV4TFpGmYOSru6sx5q4KpOJrV6aOsvVN4,3069
67
66
  ophyd_async/panda/_utils.py,sha256=VHW5kPVISyEkmse_qQcyisBkkEwMO6GG2Ago-CH1AFA,487
68
67
  ophyd_async/panda/writers/__init__.py,sha256=xy7BguVQG4HNIDBfKPjMj0KQo1tptC9LbCpEuMcVGaM,70
69
- ophyd_async/panda/writers/_hdf_writer.py,sha256=SP71y2-LTKhlNIFxLIddmtjmrg6MDwGvuwQ7X-5OP98,4698
70
- ophyd_async/panda/writers/_panda_hdf_file.py,sha256=WnGvNWuLe4KljhlmBLM4Y0HKSJCIBNWOwXxioPkGu6Y,1673
68
+ ophyd_async/panda/writers/_hdf_writer.py,sha256=D1cdERT_12nTN19p6sDYD7WqYYOGAmEhJsKArNFH46g,5138
71
69
  ophyd_async/plan_stubs/__init__.py,sha256=nO9ELG9J7fYwfVTVRWVorz4kffeszYpwk1ROh6Ha--w,405
72
- ophyd_async/plan_stubs/ensure_connected.py,sha256=1MkDu8UqVRPHLnW9IXRn-QvKiG8-rCV8T4KDbjf9K6w,557
73
- ophyd_async/plan_stubs/fly.py,sha256=fQwBeLw57-NeBsroVxKDa8kpuu6fgTWYWimbsatCL28,4999
70
+ ophyd_async/plan_stubs/ensure_connected.py,sha256=iTisEupUXrCTFikoPw9cf-BuwO_tvOmFmbkOUlPkF-E,752
71
+ ophyd_async/plan_stubs/fly.py,sha256=64bJqfvxrQHBUoJeMFY8qLlkvE_8Gw8YTu3Hek_NiLA,6421
74
72
  ophyd_async/sim/__init__.py,sha256=ScjH1g7FMo5yPACfJRZE6xGBWCHU4bKDzNQk1tqObnA,366
75
- ophyd_async/sim/pattern_generator.py,sha256=pvSk2zb82D08j2jiKAMqMAfRohGnYd_rpjUraLrCD6c,10640
76
- ophyd_async/sim/sim_pattern_detector_control.py,sha256=Ypz8IuRYAY2J243IhVbNyGr_Z-XtpJZ1qxma6NR3TgM,1838
77
- ophyd_async/sim/sim_pattern_detector_writer.py,sha256=ESpcVyHd1TP7Cojznv2hJAwLinu3XbgAiVKfX12FCII,1237
78
- ophyd_async/sim/sim_pattern_generator.py,sha256=L4jTnEVUFBRXIWq_UMHqx00YDdbGO2pjo_IuuVwpzXE,1258
73
+ ophyd_async/sim/pattern_generator.py,sha256=5MOkU6JqizxQPZ4Z6kQswHsqZv-vPhsEeo8lUSvSv4Q,7369
74
+ ophyd_async/sim/sim_pattern_detector_control.py,sha256=azkKfPYIAfH8CoCBpkBfqlmOUTTN8GOoCEemRsL0emQ,1808
75
+ ophyd_async/sim/sim_pattern_detector_writer.py,sha256=yH__i1rSHAcFc3mXJPXNQElMCyyCHxpsOdTkEad33sM,1333
76
+ ophyd_async/sim/sim_pattern_generator.py,sha256=pQbXJ5mJQHypg4MTD2FNRs85OJRV9JksYmjl0r9NSSQ,1366
79
77
  ophyd_async/sim/demo/__init__.py,sha256=9mxKpslrL89cfSj4g3og8Br3O--pMj3hhWZS-Xu6kyA,56
80
78
  ophyd_async/sim/demo/sim_motor.py,sha256=a2p5wnHXjF-V5zOFai7jnszk4kbGmrZRnUqBtkOgEfQ,3733
81
- ophyd_async-0.3.4a1.dist-info/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
82
- ophyd_async-0.3.4a1.dist-info/METADATA,sha256=JNwQkJEsOunynK3sUNPtQMHoTBBf8M7kfrl7HDTJYHM,6294
83
- ophyd_async-0.3.4a1.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
84
- ophyd_async-0.3.4a1.dist-info/entry_points.txt,sha256=O0YNJTEufO0w9BozXi-JurTy2U1_o0ypeCgJLQ727Jk,58
85
- ophyd_async-0.3.4a1.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
86
- ophyd_async-0.3.4a1.dist-info/RECORD,,
79
+ ophyd_async-0.4.0.dist-info/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
80
+ ophyd_async-0.4.0.dist-info/METADATA,sha256=iXknBXp3IJkO7yB9_P4CRNKksn_h0m_dUKCmnFbJcLE,6491
81
+ ophyd_async-0.4.0.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
82
+ ophyd_async-0.4.0.dist-info/entry_points.txt,sha256=O0YNJTEufO0w9BozXi-JurTy2U1_o0ypeCgJLQ727Jk,58
83
+ ophyd_async-0.4.0.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
84
+ ophyd_async-0.4.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (70.1.1)
2
+ Generator: setuptools (70.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,10 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Sequence
3
-
4
-
5
- @dataclass
6
- class _HDFDataset:
7
- name: str
8
- path: str
9
- shape: Sequence[int]
10
- multiplier: int