ophyd-async 0.11__py3-none-any.whl → 0.12.1__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.
@@ -15,7 +15,7 @@ from ._table import SeqTable
15
15
 
16
16
 
17
17
  class SeqTableInfo(ConfinedModel):
18
- """Info for the PandA `SeqTable` for flyscanning."""
18
+ """Info for the PandA `SeqTable` for fly scanning."""
19
19
 
20
20
  sequence_table: SeqTable = Field(strict=True)
21
21
  repeats: int = Field(ge=0)
@@ -23,7 +23,7 @@ class SeqTableInfo(ConfinedModel):
23
23
 
24
24
 
25
25
  class StaticSeqTableTriggerLogic(FlyerController[SeqTableInfo]):
26
- """For controlling the PandA `SeqTable` when flyscanning."""
26
+ """For controlling the PandA `SeqTable` when fly scanning."""
27
27
 
28
28
  def __init__(self, seq: SeqBlock) -> None:
29
29
  self.seq = seq
@@ -52,7 +52,7 @@ class StaticSeqTableTriggerLogic(FlyerController[SeqTableInfo]):
52
52
 
53
53
 
54
54
  class PcompInfo(ConfinedModel):
55
- """Info for the PandA `PcompBlock` for flyscanning."""
55
+ """Info for the PandA `PcompBlock` for fly scanning."""
56
56
 
57
57
  start_postion: int = Field(description="start position in counts")
58
58
  pulse_width: int = Field(description="width of a single pulse in counts", gt=0)
@@ -76,7 +76,7 @@ class PcompInfo(ConfinedModel):
76
76
 
77
77
 
78
78
  class StaticPcompTriggerLogic(FlyerController[PcompInfo]):
79
- """For controlling the PandA `PcompBlock` when flyscanning."""
79
+ """For controlling the PandA `PcompBlock` when fly scanning."""
80
80
 
81
81
  def __init__(self, pcomp: PcompBlock) -> None:
82
82
  self.pcomp = pcomp
@@ -1,6 +1,5 @@
1
1
  import asyncio
2
2
  from collections.abc import AsyncGenerator, AsyncIterator
3
- from pathlib import Path
4
3
 
5
4
  from bluesky.protocols import StreamAsset
6
5
  from event_model import DataKey
@@ -67,8 +66,7 @@ class PandaHDFWriter(DetectorWriter):
67
66
  describe = await self._describe(name)
68
67
 
69
68
  self._composer = HDFDocumentComposer(
70
- Path(await self.panda_data_block.hdf_directory.get_value())
71
- / Path(await self.panda_data_block.hdf_file_name.get_value()),
69
+ f"{info.directory_uri}{info.filename}.h5",
72
70
  self._datasets,
73
71
  )
74
72
 
@@ -1,11 +1,6 @@
1
1
  """Plan stubs for connecting, setting up and flying devices."""
2
2
 
3
3
  from ._ensure_connected import ensure_connected
4
- from ._fly import (
5
- fly_and_collect,
6
- prepare_static_seq_table_flyer_and_detectors_with_same_trigger,
7
- time_resolved_fly_and_collect_with_static_seq_table,
8
- )
9
4
  from ._nd_attributes import setup_ndattributes, setup_ndstats_sum
10
5
  from ._panda import apply_panda_settings
11
6
  from ._settings import (
@@ -17,9 +12,6 @@ from ._settings import (
17
12
  )
18
13
 
19
14
  __all__ = [
20
- "fly_and_collect",
21
- "prepare_static_seq_table_flyer_and_detectors_with_same_trigger",
22
- "time_resolved_fly_and_collect_with_static_seq_table",
23
15
  "ensure_connected",
24
16
  "setup_ndattributes",
25
17
  "setup_ndstats_sum",
@@ -1,204 +0,0 @@
1
- import bluesky.plan_stubs as bps
2
- from bluesky.utils import short_uid
3
-
4
- from ophyd_async.core import (
5
- DetectorTrigger,
6
- StandardDetector,
7
- StandardFlyer,
8
- TriggerInfo,
9
- in_micros,
10
- )
11
- from ophyd_async.fastcs.panda import (
12
- PandaPcompDirection,
13
- PcompInfo,
14
- SeqTable,
15
- SeqTableInfo,
16
- )
17
-
18
-
19
- def prepare_static_pcomp_flyer_and_detectors(
20
- flyer: StandardFlyer[PcompInfo],
21
- detectors: list[StandardDetector],
22
- pcomp_info: PcompInfo,
23
- trigger_info: TriggerInfo,
24
- ):
25
- """Prepare a hardware triggered flyable and one or more detectors.
26
-
27
- Prepare a hardware triggered flyable and one or more detectors with the
28
- same trigger.
29
-
30
- """
31
- for det in detectors:
32
- yield from bps.prepare(det, trigger_info, wait=False, group="prep")
33
- yield from bps.prepare(flyer, pcomp_info, wait=False, group="prep")
34
- yield from bps.wait(group="prep")
35
-
36
-
37
- def prepare_static_seq_table_flyer_and_detectors_with_same_trigger(
38
- flyer: StandardFlyer[SeqTableInfo],
39
- detectors: list[StandardDetector],
40
- number_of_frames: int,
41
- exposure: float,
42
- shutter_time: float,
43
- repeats: int = 1,
44
- period: float = 0.0,
45
- frame_timeout: float | None = None,
46
- ):
47
- """Prepare a hardware triggered flyable and one or more detectors.
48
-
49
- Prepare a hardware triggered flyable and one or more detectors with the
50
- same trigger. This method constructs TriggerInfo and a static sequence
51
- table from required parameters. The table is required to prepare the flyer,
52
- and the TriggerInfo is required to prepare the detector(s).
53
-
54
- This prepares all supplied detectors with the same trigger.
55
-
56
- """
57
- if not detectors:
58
- raise ValueError("No detectors provided. There must be at least one.")
59
-
60
- deadtime = max(det._controller.get_deadtime(exposure) for det in detectors) # noqa: SLF001
61
-
62
- trigger_info = TriggerInfo(
63
- number_of_events=number_of_frames * repeats,
64
- trigger=DetectorTrigger.CONSTANT_GATE,
65
- deadtime=deadtime,
66
- livetime=exposure,
67
- exposure_timeout=frame_timeout,
68
- )
69
- trigger_time = number_of_frames * (exposure + deadtime)
70
- pre_delay = max(period - 2 * shutter_time - trigger_time, 0)
71
-
72
- table = (
73
- # Wait for pre-delay then open shutter
74
- SeqTable.row(
75
- time1=in_micros(pre_delay),
76
- time2=in_micros(shutter_time),
77
- outa2=True,
78
- )
79
- +
80
- # Keeping shutter open, do N triggers
81
- SeqTable.row(
82
- repeats=number_of_frames,
83
- time1=in_micros(exposure),
84
- outa1=True,
85
- outb1=True,
86
- time2=in_micros(deadtime),
87
- outa2=True,
88
- )
89
- +
90
- # Add the shutter close
91
- SeqTable.row(time2=in_micros(shutter_time))
92
- )
93
-
94
- table_info = SeqTableInfo(sequence_table=table, repeats=repeats)
95
-
96
- for det in detectors:
97
- yield from bps.prepare(det, trigger_info, wait=False, group="prep")
98
- yield from bps.prepare(flyer, table_info, wait=False, group="prep")
99
- yield from bps.wait(group="prep")
100
-
101
-
102
- def fly_and_collect(
103
- stream_name: str,
104
- flyer: StandardFlyer[SeqTableInfo] | StandardFlyer[PcompInfo],
105
- detectors: list[StandardDetector],
106
- ):
107
- """Kickoff, complete and collect with a flyer and multiple detectors.
108
-
109
- This stub takes a flyer and one or more detectors that have been prepared. It
110
- declares a stream for the detectors, then kicks off the detectors and the flyer.
111
- The detectors are collected until the flyer and detectors have completed.
112
-
113
- """
114
- yield from bps.declare_stream(*detectors, name=stream_name, collect=True)
115
- yield from bps.kickoff(flyer, wait=True)
116
- for detector in detectors:
117
- yield from bps.kickoff(detector)
118
-
119
- # collect_while_completing
120
- group = short_uid(label="complete")
121
-
122
- yield from bps.complete(flyer, wait=False, group=group)
123
- for detector in detectors:
124
- yield from bps.complete(detector, wait=False, group=group)
125
-
126
- done = False
127
- while not done:
128
- try:
129
- yield from bps.wait(group=group, timeout=0.5)
130
- except TimeoutError:
131
- pass
132
- else:
133
- done = True
134
- yield from bps.collect(
135
- *detectors,
136
- return_payload=False,
137
- name=stream_name,
138
- )
139
- yield from bps.wait(group=group)
140
-
141
-
142
- def fly_and_collect_with_static_pcomp(
143
- stream_name: str,
144
- flyer: StandardFlyer[PcompInfo],
145
- detectors: list[StandardDetector],
146
- number_of_pulses: int,
147
- pulse_width: int,
148
- rising_edge_step: int,
149
- direction: PandaPcompDirection,
150
- trigger_info: TriggerInfo,
151
- ):
152
- # Set up scan and prepare trigger
153
- pcomp_info = PcompInfo(
154
- start_postion=0,
155
- pulse_width=pulse_width,
156
- rising_edge_step=rising_edge_step,
157
- number_of_pulses=number_of_pulses,
158
- direction=direction,
159
- )
160
- yield from prepare_static_pcomp_flyer_and_detectors(
161
- flyer, detectors, pcomp_info, trigger_info
162
- )
163
-
164
- # Run the fly scan
165
- yield from fly_and_collect(stream_name, flyer, detectors)
166
-
167
-
168
- def time_resolved_fly_and_collect_with_static_seq_table(
169
- stream_name: str,
170
- flyer: StandardFlyer[SeqTableInfo],
171
- detectors: list[StandardDetector],
172
- number_of_frames: int,
173
- exposure: float,
174
- shutter_time: float,
175
- repeats: int = 1,
176
- period: float = 0.0,
177
- frame_timeout: float | None = None,
178
- ):
179
- """Run a scan wth a flyer and multiple detectors.
180
-
181
- The stub demonstrates the standard basic flow for a flyscan:
182
-
183
- - Prepare the flyer and detectors with a trigger
184
- - Fly and collect:
185
- - Declare the stream and kickoff the scan
186
- - Collect while completing
187
-
188
- This needs to be used in a plan that instantates detectors and a flyer,
189
- stages/unstages the devices, and opens and closes the run.
190
-
191
- """
192
- # Set up scan and prepare trigger
193
- yield from prepare_static_seq_table_flyer_and_detectors_with_same_trigger(
194
- flyer,
195
- detectors,
196
- number_of_frames=number_of_frames,
197
- exposure=exposure,
198
- shutter_time=shutter_time,
199
- repeats=repeats,
200
- period=period,
201
- frame_timeout=frame_timeout,
202
- )
203
- # Run the fly scan
204
- yield from fly_and_collect(stream_name, flyer, detectors)
@@ -1,6 +1,7 @@
1
1
  """Used for tutorial `Using Devices`."""
2
2
 
3
3
  # Import bluesky and ophyd
4
+ from pathlib import PurePath
4
5
  from tempfile import mkdtemp
5
6
 
6
7
  import bluesky.plan_stubs as bps # noqa: F401
@@ -27,7 +28,7 @@ pattern_generator = sim.PatternGenerator()
27
28
 
28
29
  # Make a path provider that makes UUID filenames within a static
29
30
  # temporary directory
30
- path_provider = StaticPathProvider(UUIDFilenameProvider(), mkdtemp())
31
+ path_provider = StaticPathProvider(UUIDFilenameProvider(), PurePath(mkdtemp()))
31
32
 
32
33
  # All Devices created within this block will be
33
34
  # connected and named at the end of the with block
@@ -1,5 +1,4 @@
1
1
  from collections.abc import AsyncGenerator, AsyncIterator
2
- from pathlib import Path
3
2
 
4
3
  import numpy as np
5
4
  from bluesky.protocols import Hints, StreamAsset
@@ -26,14 +25,14 @@ class BlobDetectorWriter(DetectorWriter):
26
25
  ) -> None:
27
26
  self.pattern_generator = pattern_generator
28
27
  self.path_provider = path_provider
29
- self.path: Path | None = None
30
28
  self.composer: HDFDocumentComposer | None = None
31
29
  self.datasets: list[HDFDatasetDescription] = []
32
30
 
33
31
  async def open(self, name: str, exposures_per_event: int = 1) -> dict[str, DataKey]:
34
32
  path_info = self.path_provider(name)
35
- self.path = path_info.directory_path / f"{path_info.filename}.h5"
36
- self.pattern_generator.open_file(self.path, WIDTH, HEIGHT)
33
+ write_path = path_info.directory_path / f"{path_info.filename}.h5"
34
+ read_path_uri = f"{path_info.directory_uri}{path_info.filename}.h5"
35
+ self.pattern_generator.open_file(write_path, WIDTH, HEIGHT)
37
36
  self.exposures_per_event = exposures_per_event
38
37
  # We know it will write data and sum, so emit those
39
38
  self.datasets = [
@@ -52,7 +51,7 @@ class BlobDetectorWriter(DetectorWriter):
52
51
  chunk_shape=(1024,),
53
52
  ),
54
53
  ]
55
- self.composer = HDFDocumentComposer(self.path, self.datasets)
54
+ self.composer = HDFDocumentComposer(read_path_uri, self.datasets)
56
55
  describe = {
57
56
  ds.data_key: DataKey(
58
57
  source="sim://pattern-generator-hdf-file",
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import time
5
- from pathlib import Path
5
+ from pathlib import PurePath
6
6
 
7
7
  import h5py
8
8
  import numpy as np
@@ -35,7 +35,7 @@ def generate_interesting_pattern(
35
35
  class PatternFile:
36
36
  def __init__(
37
37
  self,
38
- path: Path,
38
+ path: PurePath,
39
39
  width: int = 320,
40
40
  height: int = 240,
41
41
  ):
@@ -94,7 +94,7 @@ class PatternGenerator:
94
94
  offset = 100 if high_energy else 10
95
95
  return generate_interesting_pattern(self._x, self._y, channel, offset)
96
96
 
97
- def open_file(self, path: Path, width: int, height: int):
97
+ def open_file(self, path: PurePath, width: int, height: int):
98
98
  self._file = PatternFile(path, width, height)
99
99
 
100
100
  def _get_file(self) -> PatternFile:
@@ -11,6 +11,7 @@ from ._assert import (
11
11
  assert_emitted,
12
12
  assert_reading,
13
13
  assert_value,
14
+ partial_reading,
14
15
  )
15
16
  from ._mock_signal_utils import (
16
17
  callback_on_mock_put,
@@ -47,6 +48,7 @@ __all__ = [
47
48
  "assert_configuration",
48
49
  "assert_describe_signal",
49
50
  "assert_emitted",
51
+ "partial_reading",
50
52
  # Mocking utilities
51
53
  "get_mock",
52
54
  "set_mock_value",
@@ -21,6 +21,15 @@ from ophyd_async.core import (
21
21
  from ._utils import T
22
22
 
23
23
 
24
+ def partial_reading(val: Any) -> dict[str, Any]:
25
+ """Helper function for building expected reading or configuration dicts.
26
+
27
+ :param val: Value to be wrapped in dict with "value" as the key.
28
+ :return: The dict that has wrapped the val with key "value".
29
+ """
30
+ return {"value": val}
31
+
32
+
24
33
  def approx_value(value: Any):
25
34
  """Allow any value to be compared to another in tests.
26
35
 
@@ -45,14 +54,18 @@ async def assert_value(signal: SignalR[SignalDatatypeT], value: Any) -> None:
45
54
  async def assert_reading(
46
55
  readable: AsyncReadable,
47
56
  expected_reading: Mapping[str, Mapping[str, Any]],
57
+ full_match: bool = True,
48
58
  ) -> None:
49
59
  """Assert that a readable Device has the given reading.
50
60
 
51
61
  :param readable: Device with an async ``read()`` method to get the reading from.
52
62
  :param expected_reading: The expected reading from the readable.
63
+ :param full_match: if expected_reading keys set is same as actual keys set.
64
+ true: exact match
65
+ false: expected_reading keys is subset of actual reading keys
53
66
  """
54
67
  actual_reading = await readable.read()
55
- _assert_readings_approx_equal(expected_reading, actual_reading)
68
+ _assert_readings_approx_equal(expected_reading, actual_reading, full_match)
56
69
 
57
70
 
58
71
  def _approx_reading(expected: Mapping[str, Any], actual: Reading) -> Reading:
@@ -69,16 +82,26 @@ def _approx_reading(expected: Mapping[str, Any], actual: Reading) -> Reading:
69
82
 
70
83
 
71
84
  def _assert_readings_approx_equal(
72
- expected: Mapping[str, Mapping[str, Any]], actual: Mapping[str, Reading]
85
+ expected: Mapping[str, Mapping[str, Any]],
86
+ actual: Mapping[str, Reading],
87
+ full_match: bool = True,
73
88
  ):
74
- assert actual == {
75
- k: _approx_reading(v, actual[k]) for k, v in expected.items() if k in actual
89
+ # expand the expected keys to include actual if we allow partial matches
90
+ if not full_match:
91
+ expected = dict(actual, **expected)
92
+ # now make them approximate if they are in actual so we get a nicer diff
93
+ approx_expected = {
94
+ k: _approx_reading(v, actual[k]) if k in actual else v
95
+ for k, v in expected.items()
76
96
  }
97
+ # now we can compare them
98
+ assert actual == approx_expected
77
99
 
78
100
 
79
101
  async def assert_configuration(
80
102
  configurable: AsyncConfigurable,
81
- configuration: dict[str, dict[str, Any]],
103
+ expected_configuration: dict[str, dict[str, Any]],
104
+ full_match: bool = True,
82
105
  ) -> None:
83
106
  """Assert that a configurable Device has the given configuration.
84
107
 
@@ -86,9 +109,14 @@ async def assert_configuration(
86
109
  Device with an async ``read_configuration()`` method to get the
87
110
  configuration from.
88
111
  :param configuration: The expected configuration from the configurable.
112
+ :param full_match: if expected_reading keys set is same as actual keys set.
113
+ true: exact match
114
+ false: expected_reading keys is subset of actual reading keys
89
115
  """
90
116
  actual_configuration = await configurable.read_configuration()
91
- _assert_readings_approx_equal(configuration, actual_configuration)
117
+ _assert_readings_approx_equal(
118
+ expected_configuration, actual_configuration, full_match
119
+ )
92
120
 
93
121
 
94
122
  async def assert_describe_signal(signal: SignalR, /, **metadata):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ophyd-async
3
- Version: 0.11
3
+ Version: 0.12.1
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
@@ -48,6 +48,7 @@ Requires-Dist: pyyaml
48
48
  Requires-Dist: colorlog
49
49
  Requires-Dist: pydantic>=2.0
50
50
  Requires-Dist: pydantic-numpy
51
+ Requires-Dist: stamina>=23.1.0
51
52
  Provides-Extra: sim
52
53
  Requires-Dist: h5py; extra == "sim"
53
54
  Provides-Extra: ca
@@ -120,7 +121,7 @@ The main differences from ophyd sync are:
120
121
  - Support for [EPICS][] PVA and [Tango][] as well as the traditional EPICS CA
121
122
  - Better library support for splitting the logic from the hardware interface to avoid complex class heirarchies
122
123
 
123
- It was written with the aim of implementing flyscanning in a generic and extensible way with highly customizable devices like PandABox and the Delta Tau PMAC products. Using async code makes it possible to do the "put 3 PVs in parallel, then get from another PV" logic that is common in flyscanning without the performance and complexity overhead of multiple threads.
124
+ It was written with the aim of implementing fly scanning in a generic and extensible way with highly customizable devices like PandABox and the Delta Tau PMAC products. Using async code makes it possible to do the "put 3 PVs in parallel, then get from another PV" logic that is common in fly scanning without the performance and complexity overhead of multiple threads.
124
125
 
125
126
  Devices from both ophyd sync and ophyd-async can be used in the same RunEngine and even in the same scan. This allows a per-device migration where devices are reimplemented in ophyd-async one by one.
126
127
 
@@ -1,7 +1,7 @@
1
1
  ophyd_async/__init__.py,sha256=dcAA3qsj1nNIMe5l-v2tlduZ_ypwBmyuHe45Lsq4k4w,206
2
2
  ophyd_async/__main__.py,sha256=n_U4O9bgm97OuboUB_9eK7eFiwy8BZSgXJ0OzbE0DqU,481
3
3
  ophyd_async/_docs_parser.py,sha256=gPYrigfSbYCF7QoSf2UvE-cpQu4snSssl7ZWN-kKDzI,352
4
- ophyd_async/_version.py,sha256=JQGWKvS8mTtWQI0a0XtjLQOyFpNGX620dVCNBNQBiDE,508
4
+ ophyd_async/_version.py,sha256=DzB47l1iPNTY8yuA60VuZvneNqNdRBd1svEjKxC37o4,513
5
5
  ophyd_async/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  ophyd_async/core/__init__.py,sha256=RtYk6FdJxc7lxoSReRV1D7weTRYFu9ylhNNd3DyN904,4752
7
7
  ophyd_async/core/_derived_signal.py,sha256=TuZza_j3J1Bw4QSqBYB9Ta2FyQP5BycO3nSHVtJ890Q,13015
@@ -9,23 +9,23 @@ ophyd_async/core/_derived_signal_backend.py,sha256=PYyyont_nUR9LBC9eqVwueHCMwLJf
9
9
  ophyd_async/core/_detector.py,sha256=x1o-eSkvemQ-fTk47440owkTmYhuckA2ILNOCoJlHCY,15201
10
10
  ophyd_async/core/_device.py,sha256=lSm8FBul9NTn9VO0rsAlV9pctJyUsMdU2ztEf5CqH5M,14716
11
11
  ophyd_async/core/_device_filler.py,sha256=MDz8eQQ-eEAwo-UEMxfqPfpcBuMG01tLCGR6utwVnmE,14825
12
- ophyd_async/core/_flyer.py,sha256=Rvoi2AzPwbz-dnt3WlpfJTodgZDiK5cusbutfkbr_8A,3453
13
- ophyd_async/core/_hdf_dataset.py,sha256=qh4QMJAXuOUQUciLXdMTX9yPnmWp5l-ugGCrJWUXQDQ,2954
12
+ ophyd_async/core/_flyer.py,sha256=8zKyU5aQOr_t59GIUwsYeb8NSabdvBp0swwuRe4v5VQ,3457
13
+ ophyd_async/core/_hdf_dataset.py,sha256=0bIX_ZbFSMdXqDwRtEvV-0avHnwXhjPddE5GVNmo7H8,2608
14
14
  ophyd_async/core/_log.py,sha256=DxKR4Nz3SgTaTzKBZWqt-w48yT8WUAr_3Qr223TEWRw,3587
15
15
  ophyd_async/core/_mock_signal_backend.py,sha256=SPdCbVWss6-iL9C3t9u0IvR_Ln9JeDypVd18WlivdjE,3156
16
16
  ophyd_async/core/_protocol.py,sha256=wQ_snxhTprHqEjQb1HgFwBljwolMY6A8C3xgV1PXwdU,4051
17
- ophyd_async/core/_providers.py,sha256=1XuLUw9sT1pKMfH_PsDEpIi1gulla7NfPSp3IR3KfEA,7545
17
+ ophyd_async/core/_providers.py,sha256=WBht3QCgvGc0stNcwH6z4Zr6hAz3e01-88NjsYI2w6I,9740
18
18
  ophyd_async/core/_readable.py,sha256=iBo1YwA5bsAbzLbznvmSnzKDWUuGkLh850Br3BXsgeU,11707
19
19
  ophyd_async/core/_settings.py,sha256=_ZccbXKP7j5rG6-bMKk7aaLr8hChdRDAPY_YSR71XXM,4213
20
- ophyd_async/core/_signal.py,sha256=XXbcitQ6pmQnZUjTfsAvkWXIMS-ybGTRImYBbHAaPR0,27837
20
+ ophyd_async/core/_signal.py,sha256=wKbDJYpN7zWgRf_jAARFqZwCGXcdzPRDNXwvjGUR6dw,28217
21
21
  ophyd_async/core/_signal_backend.py,sha256=PvwTbbSVEGqM-2s5BNRrKGwM_MiYL71qMxYAgyZ7wRM,6930
22
- ophyd_async/core/_soft_signal_backend.py,sha256=zrE7H2ojHY6oQBucLkFgukszrkdvbIZuavLjEUqc_xM,6227
22
+ ophyd_async/core/_soft_signal_backend.py,sha256=NJUuyaCKtBZjggt8WKi7_lKQRHasToxviuQvl5xbhLU,6222
23
23
  ophyd_async/core/_status.py,sha256=h4TtWFM7wFtpxxyAYYSITgcVzArYZdYBHbya6qIX5t0,6553
24
24
  ophyd_async/core/_table.py,sha256=ai-_W-_WMZcy9f69BDYRv9vjVl-AVeOPN_uHYoGCSsc,6905
25
25
  ophyd_async/core/_utils.py,sha256=fePvt3g7eQ6CRQcMVkMeqxcbvYZboZ2sf1fVVZL-26M,12450
26
26
  ophyd_async/core/_yaml_settings.py,sha256=Qojhku9l5kPSkTnEylCRWTe0gpw6S_XP5av5dPpqFgQ,2089
27
27
  ophyd_async/epics/__init__.py,sha256=ou4yEaH9VZHz70e8oM614-arLMQvUfQyXhRJsnEpWn8,60
28
- ophyd_async/epics/motor.py,sha256=pdXaXo4kpJAEZGXXtBxbNdnfPppqyplpP0jFsdyWVkA,8473
28
+ ophyd_async/epics/motor.py,sha256=UFolYxuaePnWNJNOFzgI-He4kBTHhJqaTywtqFFSmsk,8475
29
29
  ophyd_async/epics/signal.py,sha256=0A-supp9ajr63O6aD7F9oG0-Q26YmRjk-ZGh57-jo1Y,239
30
30
  ophyd_async/epics/adandor/__init__.py,sha256=dlitllrAdhvh16PAcVMUSSEytTDNMu6_HuYk8KD1EoY,343
31
31
  ophyd_async/epics/adandor/_andor.py,sha256=SxAIP9OLefUqKcxrxhjNzil5D8-59Ps0vADdR6scO44,1281
@@ -35,15 +35,15 @@ ophyd_async/epics/adaravis/__init__.py,sha256=ZQaJVQiwcQn9hUZADrYgBE1sDfFEwjhVBJ
35
35
  ophyd_async/epics/adaravis/_aravis.py,sha256=Ju2wuebz9_ovl-Kza39s5VQ1pV-Omt_BaIWKqP4kcGA,1315
36
36
  ophyd_async/epics/adaravis/_aravis_controller.py,sha256=WiFR7_FAAu6_88zG-yzGLsR9YcO4L6xR73Wnjw9n0i4,1908
37
37
  ophyd_async/epics/adaravis/_aravis_io.py,sha256=af5RxeXF2ligvAXwMNMKHA4QHTR_WmNFz-f18qD2dbg,855
38
- ophyd_async/epics/adcore/__init__.py,sha256=GipuBZwaAju4g15WjvGs78S4zjGVxmbPel4E29zHFvE,1583
38
+ ophyd_async/epics/adcore/__init__.py,sha256=sDvQO3TshdXfDvLGqzsSNJT95Wk7tUAmOowDwB00Td0,1625
39
39
  ophyd_async/epics/adcore/_core_detector.py,sha256=mRDaHgXCTZF-MIVsU1csoQx9jObutYDpMWayugx2-jI,2631
40
- ophyd_async/epics/adcore/_core_io.py,sha256=jm4gQUSq727xnPriuH6jFHqlDBZceKxr_XyBNj5F65U,7392
40
+ ophyd_async/epics/adcore/_core_io.py,sha256=c1GqAUdv8lAQjklbKHtraLMhPOWEttDCsH9ow7M5I0U,7690
41
41
  ophyd_async/epics/adcore/_core_logic.py,sha256=IH7iOSVIsVj4e97ClhdBFpmdMkb8TznSaLkd3ohEhUs,8884
42
- ophyd_async/epics/adcore/_core_writer.py,sha256=S58plRmbNzig-r7gubKjDVDni_nf4CASaV1OJvudbHw,8019
43
- ophyd_async/epics/adcore/_hdf_writer.py,sha256=FYM84XYFVH6m2lM3CmZiyW1Eb-chUWLyjHUz3YhH9EQ,5743
44
- ophyd_async/epics/adcore/_jpeg_writer.py,sha256=7XC4Twx_MaCBjeol27UA-hStOCQEjkEAb3ToVMPUlZ8,670
42
+ ophyd_async/epics/adcore/_core_writer.py,sha256=6OEU8fcn7ATd3dml_aBZ_LmFgVGcdbNFyg1Sx2zqV7s,8522
43
+ ophyd_async/epics/adcore/_hdf_writer.py,sha256=AvCv_5dd2HdQoE12_CR6vH2hig2EdEIWklOu6CbPVlc,5816
44
+ ophyd_async/epics/adcore/_jpeg_writer.py,sha256=VYpUWQGEjrKG2kiRGQZlBCPXVJ1BzWb9GyB9KhxPWgo,688
45
45
  ophyd_async/epics/adcore/_single_trigger.py,sha256=tFGLT1b_rZzAvbqWP-hyCccxJMRY26T5IER-VAqKXmc,1275
46
- ophyd_async/epics/adcore/_tiff_writer.py,sha256=Na30osfkgrq4VQhUzDcuS52Gy7FS08CzbgEmKwljTmk,671
46
+ ophyd_async/epics/adcore/_tiff_writer.py,sha256=197Ky9ltsJjUKNwl8_OAuoCe8dWIc7zCFs7wautwC7Y,689
47
47
  ophyd_async/epics/adcore/_utils.py,sha256=jMmZnyDwRDBq-N_x8qOWjW2RMN9uw2KuoAmukPbb404,4252
48
48
  ophyd_async/epics/adkinetix/__init__.py,sha256=A9xq3lGMrmza9lfukRixC0Up_kUDVFII8JguLr2x7Bw,308
49
49
  ophyd_async/epics/adkinetix/_kinetix.py,sha256=zZv0JZ8i1RSx7KBDn_1HGNOY0BoIP81mRK5TKq7d4eA,1302
@@ -62,12 +62,12 @@ ophyd_async/epics/advimba/_vimba.py,sha256=4XlEnsJMGDzHLuYaIDUmaxx0gtOAehn5BKBZM
62
62
  ophyd_async/epics/advimba/_vimba_controller.py,sha256=v0av2bGnaJ01w9Igksupt2IlkuBEFlAeRCPOVma-Xa4,1980
63
63
  ophyd_async/epics/advimba/_vimba_io.py,sha256=cb2Nfp05fBZAcNVXpz-rqRIRS-TiZW5DPUJOmaFyAw0,1589
64
64
  ophyd_async/epics/core/__init__.py,sha256=8NoQxEEc2Ny_L9nrD2fnGSf_2gJr1wCR1LwUeLNcIJo,588
65
- ophyd_async/epics/core/_aioca.py,sha256=py5dM5hbT2OXah_Lzt_fAZ9RdaHhv8pdUtkOF8iOYO4,13015
65
+ ophyd_async/epics/core/_aioca.py,sha256=elNR5c2-YcDUoyzuvTEVURoqx92wkVoMDNjwjeZ0WmA,13136
66
66
  ophyd_async/epics/core/_epics_connector.py,sha256=S4z_wbj-aogVcjqCyUgjhcq5Y4gDC7y6wXbsSz2nODY,1918
67
67
  ophyd_async/epics/core/_epics_device.py,sha256=wGdR24I7GSPh3HmM7jsWKZhBZgt4IyLrCn4Ut7Wx_xo,510
68
68
  ophyd_async/epics/core/_p4p.py,sha256=uWh3oWPme74G4YfeJ6k8ZlHdKOwcf8Xp1J82b9aa_JI,16407
69
69
  ophyd_async/epics/core/_pvi_connector.py,sha256=nAReSiasZA3j_0f8XhuWVO4_ck0MrusnKR9Jg-RT-ok,5584
70
- ophyd_async/epics/core/_signal.py,sha256=2Cp5f5Xb2junnVigypjb3hWu4MuMmbrcHOBgPl5Mhv4,5776
70
+ ophyd_async/epics/core/_signal.py,sha256=qAEe8mgXRMgBTcxuwN-KDGSRtJTwrhygThTDe5vA3EQ,5916
71
71
  ophyd_async/epics/core/_util.py,sha256=G2kYfwsQ5iS3EgGrGuPA8bgC_PEN_XxO28oBurIqJFQ,2522
72
72
  ophyd_async/epics/demo/__init__.py,sha256=WR2M3D8dbHcisJW2OIU2ManZu5SWez8ytZEp4jSBfDY,416
73
73
  ophyd_async/epics/demo/__main__.py,sha256=o6M0FSWduPHe2lN9yNEdsXb48NckSd54-XJGoLe20Pc,1116
@@ -85,7 +85,7 @@ ophyd_async/epics/pmac/__init__.py,sha256=RWqo5nYE2MMBdwvMxdeVG213MN38b9VPlpDHQW
85
85
  ophyd_async/epics/pmac/_pmac_io.py,sha256=yMQpZ0Osh4l8VRd2aqWQE9ebJDfh5FwM_0pp1pe8-C0,3564
86
86
  ophyd_async/epics/testing/__init__.py,sha256=aTIv4D2DYrpnGco5RQF8QuLG1SfFkIlTyM2uYEKXltA,522
87
87
  ophyd_async/epics/testing/_example_ioc.py,sha256=uUmfMXV_Pd2SMFyb0y_4uTc6gkGRUqU1cJ-XQC2ROW8,3915
88
- ophyd_async/epics/testing/_utils.py,sha256=6sqJ0BCwubSkK-WOJbmpKNqZKG0AmCoevzaMGaRmuJs,1702
88
+ ophyd_async/epics/testing/_utils.py,sha256=9gxpwaWX0HGtacu1LTupcw7viXN8G78RmuNciU_-cjs,1702
89
89
  ophyd_async/epics/testing/test_records.db,sha256=SgWQPZgtmc__JiLkH2VPwe5KZOua6ZCIgTLGT_5SDDc,3589
90
90
  ophyd_async/epics/testing/test_records_pva.db,sha256=HJAJSvLtPWG5B5dKv8OZ0_hPJxRFrDoYp6ROcF2lqyA,4202
91
91
  ophyd_async/fastcs/__init__.py,sha256=qlIM9-pjJ8yWfnzTM9-T9cw7zQLKjeeNROQTni5Dr6M,80
@@ -100,25 +100,25 @@ ophyd_async/fastcs/panda/_block.py,sha256=SM7NaWCRwLz2Pl4wgjZMrDgx3ZLdGPTw6nU0bA
100
100
  ophyd_async/fastcs/panda/_control.py,sha256=xtW3dH_MLQoycgP-4vJtYx1M9alHjWo13iu9UFTgwzY,1306
101
101
  ophyd_async/fastcs/panda/_hdf_panda.py,sha256=tL_OWHxlMQcMZGq9sxHLSeag6hP9MRIbTPn1W0u0iNI,1237
102
102
  ophyd_async/fastcs/panda/_table.py,sha256=maKGoKypEuYqTSVWGgDO6GMEKOtlDm9Dn5YiYdBzu6c,2486
103
- ophyd_async/fastcs/panda/_trigger.py,sha256=X3FV51zNq3aADeSj-mwghf_NH72_25BreTPvjkOiQTE,3400
104
- ophyd_async/fastcs/panda/_writer.py,sha256=9cXDrfzj_e8LyGoG7kvgmftt8D_TS6r0fnlO8uR1fHw,6298
105
- ophyd_async/plan_stubs/__init__.py,sha256=2ngpkB4wwqlx1dn9JPSHjQdbyWLmY6n-3XVh3RDE8-g,939
103
+ ophyd_async/fastcs/panda/_trigger.py,sha256=TLd0ST-ZgsCGpONGUe76qHOaH74TlZNIGNkh-10eRa8,3404
104
+ ophyd_async/fastcs/panda/_writer.py,sha256=UqsU44u0uIqkDNky3mIzhW3OhLeZ8TSqFS666qrRdmA,6181
105
+ ophyd_async/plan_stubs/__init__.py,sha256=sRe1Jna_6i7aKjE3pPzsP4iNMWeWdtiptLnOq9pov9M,619
106
106
  ophyd_async/plan_stubs/_ensure_connected.py,sha256=YR6VRj7koccJ4x35NV-Ugl4ZbxgAoGN9PjVIjhv0gpw,894
107
- ophyd_async/plan_stubs/_fly.py,sha256=2xFae3b3bCux_1wmwKIF1tJx1vjg2JJfJ8iQ1aUExAs,6234
107
+ ophyd_async/plan_stubs/_fly.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
108
108
  ophyd_async/plan_stubs/_nd_attributes.py,sha256=kwzyUSeidUH714gaZQtJLxCgDZtmIRyyoKBBRbvqg38,2350
109
109
  ophyd_async/plan_stubs/_panda.py,sha256=5_Mf9kGzNjXpf_YscpCUE8tgq284nOHWCG7o_LNFfII,463
110
110
  ophyd_async/plan_stubs/_settings.py,sha256=e3dGVSUV-Htay_9fKXyQTAQLdjunetGI3OBYp_oC_FY,5574
111
111
  ophyd_async/plan_stubs/_utils.py,sha256=zClRo5ve8RGia7wQnby41W-Zprj-slOA5da1LfYnuhw,45
112
112
  ophyd_async/plan_stubs/_wait_for_awaitable.py,sha256=PGct_dGezKrLhm0W_GD83dwevSccG_vsmj0WSlMNVWc,364
113
113
  ophyd_async/sim/__init__.py,sha256=TC86iJGt4u5UtRJniNEaUJbYB2C03kmjZF-jr2zPExY,709
114
- ophyd_async/sim/__main__.py,sha256=mx6natJxnvUBTQXbS4R5OGH_MZVgYiXQkoh3JBJ8NxU,1693
114
+ ophyd_async/sim/__main__.py,sha256=TPN2nc4qYdBEKpNq4FYsRMvW5a0TEFx1sM92ScIybow,1732
115
115
  ophyd_async/sim/_blob_detector.py,sha256=bJa-G2JF6pPLJx4YIEvFTG07DvQ18ZNSYbtde6qnWPY,1033
116
116
  ophyd_async/sim/_blob_detector_controller.py,sha256=y1aSNQJUPnsT2qnj2sk254Mp18anmgQy7ctHlYQZ_B0,1788
117
- ophyd_async/sim/_blob_detector_writer.py,sha256=-Qj0uSSNgqtLNe9wwsczbWKnSXLKDXISlwX1EHR_-UY,3327
117
+ ophyd_async/sim/_blob_detector_writer.py,sha256=_Pd0OaP4_mZfwxtUF35v7hsktLP_wYljR4nylr5CzJo,3346
118
118
  ophyd_async/sim/_mirror_horizontal.py,sha256=Jsqa8Snjy1jQDboZtAQFJjGor5uKk8FBC7OCe-GoZDw,1478
119
119
  ophyd_async/sim/_mirror_vertical.py,sha256=HUD44mYT0jQ0GKiQKxD7k_7y6o6OdE6TztgdPUJIK_g,2085
120
120
  ophyd_async/sim/_motor.py,sha256=7s2jBNwWm4CI6I6l_LEpe7z61QdWy82JdZBKSFOnYe4,8994
121
- ophyd_async/sim/_pattern_generator.py,sha256=FjPEWiBQh_7tYP_8WPhbVXnTGPPOaV6By7Skz7YNIrY,3722
121
+ ophyd_async/sim/_pattern_generator.py,sha256=kuxvyX2gIxrywhQRhaO1g8YluBT7LBkE20IsurZS-6o,3734
122
122
  ophyd_async/sim/_point_detector.py,sha256=nXgL_1aJZciNBw8Zr2wMYaMbzzAEKXV3yV8FQz2nS_4,2940
123
123
  ophyd_async/sim/_stage.py,sha256=qaeyZbUVL1v2pTHJiZxq-y6BKpA1l_DAKyzAQppQx70,772
124
124
  ophyd_async/tango/__init__.py,sha256=g9xzjlzPpUAP12YI-kYwfAoLSYPAQdL1S11R2c-cius,60
@@ -137,16 +137,16 @@ ophyd_async/tango/demo/_tango/__init__.py,sha256=FfONT7vM49nNo3a1Lv-LcMZO9EHv6bv
137
137
  ophyd_async/tango/demo/_tango/_servers.py,sha256=putvERDyibibaTbhdWyqZB_axj2fURXqzDsZb9oSW14,2991
138
138
  ophyd_async/tango/testing/__init__.py,sha256=SYXPAS00ny3jlUMOJKpaewO4ljPjK1_z1smj7IfsBQg,148
139
139
  ophyd_async/tango/testing/_one_of_everything.py,sha256=tsxWgy2f_m9f0FH4XCVO_I8OtEquKbJQZbr4KaXMJL4,6571
140
- ophyd_async/testing/__init__.py,sha256=f53HUj2hpIfrza9OlcOpHmq5wnziQNwixawAK4F1xgc,1698
140
+ ophyd_async/testing/__init__.py,sha256=jDBzUAHGDMfkhd-_9u0CJWEq0E0sPrIGGlLmVzEyxY8,1742
141
141
  ophyd_async/testing/__pytest_assert_rewrite.py,sha256=_SU2UfChPgEf7CFY7aYH2B7MLp-07_qYnVLyu6QtDL8,129
142
- ophyd_async/testing/_assert.py,sha256=FrMgMfo-ABq_cMT-hJmoaTxhAY4TwAvGe4ae1SF1rME,7657
142
+ ophyd_async/testing/_assert.py,sha256=zDTJh7QPhaJpzhnuFuejGKTKbKAs7ZNKx3sVsXBMrTU,8758
143
143
  ophyd_async/testing/_mock_signal_utils.py,sha256=d-n_923ii59-ae9TbqVuIK9MAJpDmu0k47fzgJLj8t8,5195
144
144
  ophyd_async/testing/_one_of_everything.py,sha256=Di0hPoKwrDOSsx50-2UdSHM2EbIKrPG9s0Vp11nE9V8,4773
145
145
  ophyd_async/testing/_single_derived.py,sha256=5-HOTzgePcZ354NK_ssVpyIbJoJmKyjVQCxSwQXUC-4,2730
146
146
  ophyd_async/testing/_utils.py,sha256=zClRo5ve8RGia7wQnby41W-Zprj-slOA5da1LfYnuhw,45
147
147
  ophyd_async/testing/_wait_for_pending.py,sha256=YZAR48n-CW0GsPey3zFRzMJ4byDAr3HvMIoawjmTrHw,732
148
- ophyd_async-0.11.dist-info/licenses/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
149
- ophyd_async-0.11.dist-info/METADATA,sha256=0H2kxSQoFHWEs8JMhMkrrQRw49Bh0wV4ulAnW5pZ6Ks,7077
150
- ophyd_async-0.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
151
- ophyd_async-0.11.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
152
- ophyd_async-0.11.dist-info/RECORD,,
148
+ ophyd_async-0.12.1.dist-info/licenses/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
149
+ ophyd_async-0.12.1.dist-info/METADATA,sha256=Vn04AobiRZJ4KZJ7Na9c3whRj0M1eEmWBbtWuW03i3I,7112
150
+ ophyd_async-0.12.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
151
+ ophyd_async-0.12.1.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
152
+ ophyd_async-0.12.1.dist-info/RECORD,,