ophyd-async 0.11__py3-none-any.whl → 0.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ophyd_async/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.11'
21
- __version_tuple__ = version_tuple = (0, 11)
20
+ __version__ = version = '0.12'
21
+ __version_tuple__ = version_tuple = (0, 12)
@@ -17,15 +17,15 @@ class FlyerController(ABC, Generic[T]):
17
17
 
18
18
  @abstractmethod
19
19
  async def prepare(self, value: T) -> Any:
20
- """Move to the start of the flyscan."""
20
+ """Move to the start of the fly scan."""
21
21
 
22
22
  @abstractmethod
23
23
  async def kickoff(self):
24
- """Start the flyscan."""
24
+ """Start the fly scan."""
25
25
 
26
26
  @abstractmethod
27
27
  async def complete(self):
28
- """Block until the flyscan is done."""
28
+ """Block until the fly scan is done."""
29
29
 
30
30
  @abstractmethod
31
31
  async def stop(self):
@@ -101,7 +101,7 @@ class StandardFlyer(
101
101
  return AsyncStatus(self._prepare(value))
102
102
 
103
103
  async def _prepare(self, value: T) -> None:
104
- # Move to start and setup the flyscan
104
+ # Move to start and setup the fly scan
105
105
  await self._trigger_logic.prepare(value)
106
106
 
107
107
  @AsyncStatus.wrap
@@ -17,6 +17,7 @@ from bluesky.protocols import (
17
17
  Subscribable,
18
18
  )
19
19
  from event_model import DataKey
20
+ from stamina import retry_context
20
21
 
21
22
  from ._device import Device, DeviceConnector
22
23
  from ._mock_signal_backend import MockSignalBackend
@@ -89,9 +90,11 @@ class Signal(Device, Generic[SignalDatatypeT]):
89
90
  backend: SignalBackend[SignalDatatypeT],
90
91
  timeout: float | None = DEFAULT_TIMEOUT,
91
92
  name: str = "",
93
+ attempts: int = 1,
92
94
  ) -> None:
93
95
  super().__init__(name=name, connector=SignalConnector(backend))
94
96
  self._timeout = timeout
97
+ self._attempts = attempts
95
98
 
96
99
  @property
97
100
  def source(self) -> str:
@@ -144,7 +147,8 @@ class _SignalCache(Generic[SignalDatatypeT]):
144
147
  )
145
148
  self._reading = reading
146
149
  self._valid.set()
147
- for function, want_value in self._listeners.items():
150
+ items = self._listeners.copy().items()
151
+ for function, want_value in items:
148
152
  self._notify(function, want_value)
149
153
 
150
154
  def _notify(
@@ -287,7 +291,16 @@ class SignalW(Signal[SignalDatatypeT], Movable):
287
291
  timeout = self._timeout
288
292
  source = self._connector.backend.source(self.name, read=False)
289
293
  self.log.debug(f"Putting value {value} to backend at source {source}")
290
- await _wait_for(self._connector.backend.put(value, wait=wait), timeout, source)
294
+ async for attempt in retry_context(
295
+ on=asyncio.TimeoutError,
296
+ attempts=self._attempts,
297
+ wait_initial=0,
298
+ wait_jitter=0,
299
+ ):
300
+ with attempt:
301
+ await _wait_for(
302
+ self._connector.backend.put(value, wait=wait), timeout, source
303
+ )
291
304
  self.log.debug(f"Successfully put value {value} to backend at source {source}")
292
305
 
293
306
 
@@ -94,6 +94,7 @@ def epics_signal_rw(
94
94
  write_pv: str | None = None,
95
95
  name: str = "",
96
96
  timeout: float = DEFAULT_TIMEOUT,
97
+ attempts: int = 1,
97
98
  ) -> SignalRW[SignalDatatypeT]:
98
99
  """Create a `SignalRW` backed by 1 or 2 EPICS PVs.
99
100
 
@@ -104,7 +105,7 @@ def epics_signal_rw(
104
105
  :param timeout: A timeout to be used when reading (not connecting) this signal
105
106
  """
106
107
  backend = _epics_signal_backend(datatype, read_pv, write_pv or read_pv)
107
- return SignalRW(backend, name=name, timeout=timeout)
108
+ return SignalRW(backend, name=name, timeout=timeout, attempts=attempts)
108
109
 
109
110
 
110
111
  def epics_signal_rw_rbv(
@@ -113,6 +114,7 @@ def epics_signal_rw_rbv(
113
114
  read_suffix: str = "_RBV",
114
115
  name: str = "",
115
116
  timeout: float = DEFAULT_TIMEOUT,
117
+ attempts: int = 1,
116
118
  ) -> SignalRW[SignalDatatypeT]:
117
119
  """Create a `SignalRW` backed by 1 or 2 EPICS PVs, with a suffix on the readback pv.
118
120
 
@@ -128,7 +130,9 @@ def epics_signal_rw_rbv(
128
130
  else:
129
131
  read_pv = f"{write_pv}{read_suffix}"
130
132
 
131
- return epics_signal_rw(datatype, read_pv, write_pv, name, timeout=timeout)
133
+ return epics_signal_rw(
134
+ datatype, read_pv, write_pv, name, timeout=timeout, attempts=attempts
135
+ )
132
136
 
133
137
 
134
138
  def epics_signal_r(
@@ -153,6 +157,7 @@ def epics_signal_w(
153
157
  write_pv: str,
154
158
  name: str = "",
155
159
  timeout: float = DEFAULT_TIMEOUT,
160
+ attempts: int = 1,
156
161
  ) -> SignalW[SignalDatatypeT]:
157
162
  """Create a `SignalW` backed by 1 EPICS PVs.
158
163
 
@@ -162,7 +167,7 @@ def epics_signal_w(
162
167
  :param timeout: A timeout to be used when reading (not connecting) this signal
163
168
  """
164
169
  backend = _epics_signal_backend(datatype, write_pv, write_pv)
165
- return SignalW(backend, name=name, timeout=timeout)
170
+ return SignalW(backend, name=name, timeout=timeout, attempts=attempts)
166
171
 
167
172
 
168
173
  def epics_signal_x(
@@ -108,7 +108,7 @@ class Motor(
108
108
 
109
109
  @AsyncStatus.wrap
110
110
  async def prepare(self, value: FlyMotorInfo):
111
- """Move to the beginning of a suitable run-up distance ready for a flyscan."""
111
+ """Move to the beginning of a suitable run-up distance ready for a fly scan."""
112
112
  self._fly_info = value
113
113
 
114
114
  # Velocity, at which motor travels from start_position to end_position, in motor
@@ -147,7 +147,7 @@ class Motor(
147
147
  await self.velocity.set(abs(max_speed))
148
148
  await self.set(ramp_up_start_pos)
149
149
 
150
- # Set velocity we will be using for the flyscan
150
+ # Set velocity we will be using for the fly scan
151
151
  await self.velocity.set(abs(value.velocity))
152
152
 
153
153
  @AsyncStatus.wrap
@@ -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,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)
@@ -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
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=DJRqD0JYfzL1dCvH3-tt5p9TxBGyEU8MKFd2lrz6Yqw,508
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,7 +9,7 @@ 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
12
+ ophyd_async/core/_flyer.py,sha256=8zKyU5aQOr_t59GIUwsYeb8NSabdvBp0swwuRe4v5VQ,3457
13
13
  ophyd_async/core/_hdf_dataset.py,sha256=qh4QMJAXuOUQUciLXdMTX9yPnmWp5l-ugGCrJWUXQDQ,2954
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
@@ -17,7 +17,7 @@ ophyd_async/core/_protocol.py,sha256=wQ_snxhTprHqEjQb1HgFwBljwolMY6A8C3xgV1PXwdU
17
17
  ophyd_async/core/_providers.py,sha256=1XuLUw9sT1pKMfH_PsDEpIi1gulla7NfPSp3IR3KfEA,7545
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
22
  ophyd_async/core/_soft_signal_backend.py,sha256=zrE7H2ojHY6oQBucLkFgukszrkdvbIZuavLjEUqc_xM,6227
23
23
  ophyd_async/core/_status.py,sha256=h4TtWFM7wFtpxxyAYYSITgcVzArYZdYBHbya6qIX5t0,6553
@@ -25,7 +25,7 @@ ophyd_async/core/_table.py,sha256=ai-_W-_WMZcy9f69BDYRv9vjVl-AVeOPN_uHYoGCSsc,69
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
@@ -67,7 +67,7 @@ ophyd_async/epics/core/_epics_connector.py,sha256=S4z_wbj-aogVcjqCyUgjhcq5Y4gDC7
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
@@ -100,11 +100,11 @@ 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
103
+ ophyd_async/fastcs/panda/_trigger.py,sha256=TLd0ST-ZgsCGpONGUe76qHOaH74TlZNIGNkh-10eRa8,3404
104
104
  ophyd_async/fastcs/panda/_writer.py,sha256=9cXDrfzj_e8LyGoG7kvgmftt8D_TS6r0fnlO8uR1fHw,6298
105
- ophyd_async/plan_stubs/__init__.py,sha256=2ngpkB4wwqlx1dn9JPSHjQdbyWLmY6n-3XVh3RDE8-g,939
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
@@ -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.dist-info/licenses/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
149
+ ophyd_async-0.12.dist-info/METADATA,sha256=mpFROvfJrpnj_A-CMYhK4YST2f8ZrkvNkvWg9dVFNVc,7110
150
+ ophyd_async-0.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
151
+ ophyd_async-0.12.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
152
+ ophyd_async-0.12.dist-info/RECORD,,