dls-dodal 1.33.0__py3-none-any.whl → 1.35.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 (89) hide show
  1. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/METADATA +3 -3
  2. dls_dodal-1.35.0.dist-info/RECORD +147 -0
  3. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/WHEEL +1 -1
  4. dodal/__init__.py +8 -0
  5. dodal/_version.py +2 -2
  6. dodal/beamline_specific_utils/i03.py +6 -2
  7. dodal/beamlines/__init__.py +2 -3
  8. dodal/beamlines/i03.py +41 -9
  9. dodal/beamlines/i04.py +26 -4
  10. dodal/beamlines/i10.py +257 -0
  11. dodal/beamlines/i22.py +25 -13
  12. dodal/beamlines/i24.py +11 -11
  13. dodal/beamlines/p38.py +24 -13
  14. dodal/common/beamlines/beamline_utils.py +1 -2
  15. dodal/common/crystal_metadata.py +61 -0
  16. dodal/common/signal_utils.py +10 -14
  17. dodal/common/types.py +2 -7
  18. dodal/devices/CTAB.py +1 -1
  19. dodal/devices/aperture.py +1 -1
  20. dodal/devices/aperturescatterguard.py +20 -8
  21. dodal/devices/apple2_undulator.py +603 -0
  22. dodal/devices/areadetector/plugins/CAM.py +29 -0
  23. dodal/devices/areadetector/plugins/MJPG.py +51 -106
  24. dodal/devices/attenuator.py +1 -1
  25. dodal/devices/backlight.py +11 -11
  26. dodal/devices/cryostream.py +3 -5
  27. dodal/devices/dcm.py +26 -2
  28. dodal/devices/detector/detector_motion.py +3 -5
  29. dodal/devices/diamond_filter.py +46 -0
  30. dodal/devices/eiger.py +6 -2
  31. dodal/devices/eiger_odin.py +48 -39
  32. dodal/devices/fast_grid_scan.py +1 -1
  33. dodal/devices/fluorescence_detector_motion.py +5 -7
  34. dodal/devices/focusing_mirror.py +26 -19
  35. dodal/devices/hutch_shutter.py +4 -5
  36. dodal/devices/i10/i10_apple2.py +399 -0
  37. dodal/devices/i10/i10_setting_data.py +7 -0
  38. dodal/devices/i22/dcm.py +50 -83
  39. dodal/devices/i22/fswitch.py +5 -5
  40. dodal/devices/i24/aperture.py +3 -5
  41. dodal/devices/i24/beamstop.py +3 -5
  42. dodal/devices/i24/dcm.py +1 -1
  43. dodal/devices/i24/dual_backlight.py +9 -11
  44. dodal/devices/i24/pmac.py +35 -46
  45. dodal/devices/i24/vgonio.py +16 -0
  46. dodal/devices/ipin.py +5 -3
  47. dodal/devices/linkam3.py +7 -7
  48. dodal/devices/oav/oav_calculations.py +22 -0
  49. dodal/devices/oav/oav_detector.py +118 -83
  50. dodal/devices/oav/oav_parameters.py +50 -104
  51. dodal/devices/oav/oav_to_redis_forwarder.py +77 -35
  52. dodal/devices/oav/pin_image_recognition/__init__.py +9 -7
  53. dodal/devices/oav/{grid_overlay.py → snapshots/grid_overlay.py} +16 -59
  54. dodal/devices/oav/snapshots/snapshot_with_beam_centre.py +64 -0
  55. dodal/devices/oav/snapshots/snapshot_with_grid.py +57 -0
  56. dodal/devices/oav/utils.py +28 -27
  57. dodal/devices/p99/sample_stage.py +3 -5
  58. dodal/devices/pgm.py +40 -0
  59. dodal/devices/qbpm.py +18 -0
  60. dodal/devices/robot.py +5 -5
  61. dodal/devices/smargon.py +3 -3
  62. dodal/devices/synchrotron.py +9 -4
  63. dodal/devices/tetramm.py +9 -9
  64. dodal/devices/thawer.py +13 -7
  65. dodal/devices/undulator.py +7 -6
  66. dodal/devices/util/adjuster_plans.py +1 -1
  67. dodal/devices/util/epics_util.py +1 -1
  68. dodal/devices/util/lookup_tables.py +4 -5
  69. dodal/devices/watsonmarlow323_pump.py +45 -0
  70. dodal/devices/webcam.py +9 -2
  71. dodal/devices/xbpm_feedback.py +3 -5
  72. dodal/devices/xspress3/xspress3.py +8 -9
  73. dodal/devices/xspress3/xspress3_channel.py +3 -5
  74. dodal/devices/zebra.py +12 -8
  75. dodal/devices/zebra_controlled_shutter.py +5 -6
  76. dodal/devices/zocalo/__init__.py +2 -2
  77. dodal/devices/zocalo/zocalo_constants.py +3 -0
  78. dodal/devices/zocalo/zocalo_interaction.py +2 -1
  79. dodal/devices/zocalo/zocalo_results.py +105 -89
  80. dodal/plans/data_session_metadata.py +2 -2
  81. dodal/plans/motor_util_plans.py +11 -9
  82. dodal/utils.py +11 -0
  83. dls_dodal-1.33.0.dist-info/RECORD +0 -136
  84. dodal/beamlines/i04_1.py +0 -140
  85. dodal/devices/i24/i24_vgonio.py +0 -17
  86. dodal/devices/oav/oav_errors.py +0 -35
  87. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/LICENSE +0 -0
  88. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/entry_points.txt +0 -0
  89. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/top_level.txt +0 -0
dodal/devices/zebra.py CHANGED
@@ -9,10 +9,12 @@ from ophyd_async.core import (
9
9
  DeviceVector,
10
10
  SignalRW,
11
11
  StandardReadable,
12
+ StrictEnum,
12
13
  observe_value,
13
14
  )
14
- from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw
15
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
15
16
 
17
+ # These constants refer to I03's Zebra. See https://github.com/DiamondLightSource/dodal/issues/772
16
18
  # Sources
17
19
  DISCONNECT = 0
18
20
  IN1_TTL = 1
@@ -39,22 +41,24 @@ TTL_PANDA = 4
39
41
 
40
42
  # The AND gate that controls the automatic shutter
41
43
  AUTO_SHUTTER_GATE = 2
42
- # The input that triggers the automatic shutter
43
- AUTO_SHUTTER_INPUT = 1
44
44
 
45
+ # The first two inputs of the auto shutter gate.
46
+ AUTO_SHUTTER_INPUT_1 = 1
47
+ AUTO_SHUTTER_INPUT_2 = 2
45
48
 
46
- class ArmSource(str, Enum):
49
+
50
+ class ArmSource(StrictEnum):
47
51
  SOFT = "Soft"
48
52
  EXTERNAL = "External"
49
53
 
50
54
 
51
- class TrigSource(str, Enum):
55
+ class TrigSource(StrictEnum):
52
56
  POSITION = "Position"
53
57
  TIME = "Time"
54
58
  EXTERNAL = "External"
55
59
 
56
60
 
57
- class EncEnum(str, Enum):
61
+ class EncEnum(StrictEnum):
58
62
  Enc1 = "Enc1"
59
63
  Enc2 = "Enc2"
60
64
  Enc3 = "Enc3"
@@ -76,7 +80,7 @@ class I24Axes:
76
80
  VGON_YH = EncEnum.Enc4
77
81
 
78
82
 
79
- class RotationDirection(str, Enum):
83
+ class RotationDirection(StrictEnum):
80
84
  POSITIVE = "Positive"
81
85
  NEGATIVE = "Negative"
82
86
 
@@ -90,7 +94,7 @@ class ArmDemand(Enum):
90
94
  DISARM = 0
91
95
 
92
96
 
93
- class SoftInState(str, Enum):
97
+ class SoftInState(StrictEnum):
94
98
  YES = "Yes"
95
99
  NO = "No"
96
100
 
@@ -1,21 +1,20 @@
1
- from enum import Enum
2
-
3
1
  from bluesky.protocols import Movable
4
2
  from ophyd_async.core import (
5
3
  DEFAULT_TIMEOUT,
6
4
  AsyncStatus,
7
5
  StandardReadable,
6
+ StrictEnum,
8
7
  wait_for_value,
9
8
  )
10
- from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw, epics_signal_w
9
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_w
11
10
 
12
11
 
13
- class ZebraShutterState(str, Enum):
12
+ class ZebraShutterState(StrictEnum):
14
13
  CLOSE = "Close"
15
14
  OPEN = "Open"
16
15
 
17
16
 
18
- class ZebraShutterControl(str, Enum):
17
+ class ZebraShutterControl(StrictEnum):
19
18
  MANUAL = "Manual"
20
19
  AUTO = "Auto"
21
20
 
@@ -26,7 +25,7 @@ class ZebraShutter(StandardReadable, Movable):
26
25
  Internally in the zebra there are two AND gates, one for manual control and one for
27
26
  automatic control. A soft input (aliased to control_mode) will switch between
28
27
  which of these AND gates to use. For the manual gate the shutter is then controlled
29
- by a different soft input (aliased to _manual_position_setpoint). Both these AND
28
+ by a different soft input (aliased to manual_position_setpoint). Both these AND
30
29
  gates then feed into an OR gate, which then feeds to the shutter."""
31
30
 
32
31
  def __init__(self, prefix: str, name: str):
@@ -4,14 +4,14 @@ from dodal.devices.zocalo.zocalo_results import (
4
4
  NoZocaloSubscription,
5
5
  XrcResult,
6
6
  ZocaloResults,
7
- get_processing_result,
7
+ get_full_processing_results,
8
8
  )
9
9
 
10
10
  __all__ = [
11
11
  "ZocaloResults",
12
12
  "XrcResult",
13
13
  "ZocaloTrigger",
14
- "get_processing_result",
14
+ "get_full_processing_results",
15
15
  "ZOCALO_READING_PLAN_NAME",
16
16
  "NoResultsFromZocalo",
17
17
  "NoZocaloSubscription",
@@ -0,0 +1,3 @@
1
+ from dodal.utils import is_test_mode
2
+
3
+ ZOCALO_ENV = "dev_bluesky" if is_test_mode() else "bluesky"
@@ -7,6 +7,7 @@ from dataclasses import dataclass
7
7
  import zocalo.configuration
8
8
  from workflows.transport import lookup
9
9
 
10
+ from dodal.devices.zocalo.zocalo_constants import ZOCALO_ENV
10
11
  from dodal.log import LOGGER
11
12
 
12
13
 
@@ -56,7 +57,7 @@ class ZocaloTrigger:
56
57
 
57
58
  see https://github.com/DiamondLightSource/dodal/wiki/How-to-Interact-with-Zocalo"""
58
59
 
59
- def __init__(self, environment: str = "artemis"):
60
+ def __init__(self, environment: str = ZOCALO_ENV):
60
61
  self.zocalo_environment: str = environment
61
62
 
62
63
  def _send_to_zocalo(self, parameters: dict):
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
- from collections import OrderedDict
3
2
  from collections.abc import Generator, Sequence
4
3
  from enum import Enum
4
+ from inspect import get_annotations
5
5
  from queue import Empty, Queue
6
6
  from typing import Any, TypedDict
7
7
 
@@ -9,17 +9,19 @@ import bluesky.plan_stubs as bps
9
9
  import numpy as np
10
10
  import workflows.recipe
11
11
  import workflows.transport
12
- from bluesky.protocols import Descriptor, Triggerable
12
+ from bluesky.protocols import Triggerable
13
+ from bluesky.utils import Msg
13
14
  from deepdiff import DeepDiff
14
15
  from numpy.typing import NDArray
15
16
  from ophyd_async.core import (
16
17
  AsyncStatus,
17
- HintedSignal,
18
18
  StandardReadable,
19
+ StandardReadableFormat,
19
20
  soft_signal_r_and_setter,
20
21
  )
21
22
  from workflows.transport.common_transport import CommonTransport
22
23
 
24
+ from dodal.devices.zocalo.zocalo_constants import ZOCALO_ENV
23
25
  from dodal.devices.zocalo.zocalo_interaction import _get_zocalo_connection
24
26
  from dodal.log import LOGGER
25
27
 
@@ -51,7 +53,7 @@ ZOCALO_STAGE_GROUP = "clear zocalo queue"
51
53
 
52
54
 
53
55
  class XrcResult(TypedDict):
54
- centre_of_mass: list[int]
56
+ centre_of_mass: list[float]
55
57
  max_voxel: list[int]
56
58
  max_count: int
57
59
  n_voxels: int
@@ -114,7 +116,7 @@ class ZocaloResults(StandardReadable, Triggerable):
114
116
  def __init__(
115
117
  self,
116
118
  name: str = "zocalo",
117
- zocalo_environment: str = "dev_artemis",
119
+ zocalo_environment: str = ZOCALO_ENV,
118
120
  channel: str = "xrc.i03",
119
121
  sort_key: str = DEFAULT_SORT_KEY.value,
120
122
  timeout_s: float = DEFAULT_TIMEOUT,
@@ -130,14 +132,23 @@ class ZocaloResults(StandardReadable, Triggerable):
130
132
  self.transport: CommonTransport | None = None
131
133
  self.use_cpu_and_gpu = use_cpu_and_gpu
132
134
 
133
- self.results, self._results_setter = soft_signal_r_and_setter(
134
- list[XrcResult], name="results"
135
+ self.centre_of_mass, self._com_setter = soft_signal_r_and_setter(
136
+ NDArray[np.uint64], name="centre_of_mass"
135
137
  )
136
- self.centres_of_mass, self._com_setter = soft_signal_r_and_setter(
137
- NDArray[np.uint64], name="centres_of_mass"
138
+ self.bounding_box, self._bounding_box_setter = soft_signal_r_and_setter(
139
+ NDArray[np.uint64], name="bounding_box"
138
140
  )
139
- self.bbox_sizes, self._bbox_setter = soft_signal_r_and_setter(
140
- NDArray[np.uint64], "bbox_sizes", self.name
141
+ self.max_voxel, self._max_voxel_setter = soft_signal_r_and_setter(
142
+ NDArray[np.uint64], name="max_voxel"
143
+ )
144
+ self.max_count, self._max_count_setter = soft_signal_r_and_setter(
145
+ NDArray[np.uint64], name="max_count"
146
+ )
147
+ self.n_voxels, self._n_voxels_setter = soft_signal_r_and_setter(
148
+ NDArray[np.uint64], name="n_voxels"
149
+ )
150
+ self.total_count, self._total_count_setter = soft_signal_r_and_setter(
151
+ NDArray[np.uint64], name="total_count"
141
152
  )
142
153
  self.ispyb_dcid, self._ispyb_dcid_setter = soft_signal_r_and_setter(
143
154
  int, name="ispyb_dcid"
@@ -147,22 +158,27 @@ class ZocaloResults(StandardReadable, Triggerable):
147
158
  )
148
159
  self.add_readables(
149
160
  [
150
- self.results,
151
- self.centres_of_mass,
152
- self.bbox_sizes,
161
+ self.max_voxel,
162
+ self.max_count,
163
+ self.n_voxels,
164
+ self.total_count,
165
+ self.centre_of_mass,
166
+ self.bounding_box,
153
167
  self.ispyb_dcid,
154
168
  self.ispyb_dcgid,
155
169
  ],
156
- wrapper=HintedSignal,
170
+ format=StandardReadableFormat.HINTED_SIGNAL,
157
171
  )
158
172
  super().__init__(name)
159
173
 
160
174
  async def _put_results(self, results: Sequence[XrcResult], recipe_parameters):
161
- self._results_setter(list(results))
162
175
  centres_of_mass = np.array([r["centre_of_mass"] for r in results])
163
- bbox_sizes = np.array([bbox_size(r) for r in results])
164
176
  self._com_setter(centres_of_mass)
165
- self._bbox_setter(bbox_sizes)
177
+ self._bounding_box_setter(np.array([r["bounding_box"] for r in results]))
178
+ self._max_voxel_setter(np.array([r["max_voxel"] for r in results]))
179
+ self._max_count_setter(np.array([r["max_count"] for r in results]))
180
+ self._n_voxels_setter(np.array([r["n_voxels"] for r in results]))
181
+ self._total_count_setter(np.array([r["total_count"] for r in results]))
166
182
  self._ispyb_dcid_setter(recipe_parameters["dcid"])
167
183
  self._ispyb_dcgid_setter(recipe_parameters["dcgid"])
168
184
 
@@ -229,16 +245,19 @@ class ZocaloResults(StandardReadable, Triggerable):
229
245
  source_of_second_results = source_from_results(
230
246
  raw_results_two_sources[1]
231
247
  )
232
-
233
- # Compare results from both sources and warn if they aren't the same
234
- differences_str = get_dict_differences(
235
- raw_results_two_sources[0]["results"][0],
236
- source_of_first_results,
237
- raw_results_two_sources[1]["results"][0],
238
- source_of_second_results,
239
- )
240
- if differences_str:
241
- LOGGER.warning(differences_str)
248
+ first_results = raw_results_two_sources[0]["results"]
249
+ second_results = raw_results_two_sources[1]["results"]
250
+
251
+ if first_results and second_results:
252
+ # Compare results from both sources and warn if they aren't the same
253
+ differences_str = get_dict_differences(
254
+ first_results[0],
255
+ source_of_first_results,
256
+ second_results[0],
257
+ source_of_second_results,
258
+ )
259
+ if differences_str:
260
+ LOGGER.warning(differences_str)
242
261
 
243
262
  # Always use CPU results
244
263
  raw_results = (
@@ -283,48 +302,6 @@ class ZocaloResults(StandardReadable, Triggerable):
283
302
  finally:
284
303
  self._kickoff_run = False
285
304
 
286
- async def describe(self) -> dict[str, Descriptor]:
287
- zocalo_array_type: Descriptor = {
288
- "source": f"zocalo_service:{self.zocalo_environment}",
289
- "dtype": "array",
290
- "shape": [-1, 3],
291
- }
292
- zocalo_int_type: Descriptor = {
293
- "source": f"zocalo_service:{self.zocalo_environment}",
294
- "dtype": "integer",
295
- "shape": [0],
296
- }
297
- return OrderedDict(
298
- [
299
- (
300
- self._name + "-results",
301
- {
302
- "source": f"zocalo_service:{self.zocalo_environment}",
303
- "dtype": "array",
304
- "shape": [
305
- -1,
306
- ], # TODO describe properly - see https://github.com/DiamondLightSource/dodal/issues/253
307
- },
308
- ),
309
- (
310
- self._name + "-centres_of_mass",
311
- zocalo_array_type,
312
- ),
313
- (
314
- self._name + "-bbox_sizes",
315
- zocalo_array_type,
316
- ),
317
- (
318
- self._name + "-ispyb_dcid",
319
- zocalo_int_type,
320
- ),
321
- (
322
- self._name + "-ispyb_dcgid",
323
- zocalo_int_type,
324
- ),
325
- ],
326
- )
327
-
328
305
  def _subscribe_to_results(self):
329
306
  self.transport = _get_zocalo_connection(self.zocalo_environment)
330
307
 
@@ -361,23 +338,62 @@ class ZocaloResults(StandardReadable, Triggerable):
361
338
  )
362
339
 
363
340
 
364
- def get_processing_result(
341
+ def _corrected_xrc_result(uncorrected: XrcResult) -> XrcResult:
342
+ corrected = XrcResult(**uncorrected)
343
+ corrected["centre_of_mass"] = [
344
+ coord - 0.5 for coord in uncorrected["centre_of_mass"]
345
+ ]
346
+ return corrected
347
+
348
+
349
+ def get_full_processing_results(
365
350
  zocalo: ZocaloResults,
366
- ) -> Generator[Any, Any, tuple[np.ndarray, np.ndarray] | tuple[None, None]]:
367
- """A minimal plan which will extract the top ranked xray centre and crystal bounding
368
- box size from the zocalo results. Returns (None, None) if no crystals were found."""
369
-
370
- LOGGER.info("Getting zocalo processing results.")
371
- centres_of_mass = yield from bps.rd(zocalo.centres_of_mass, default_value=[]) # type: ignore
372
- LOGGER.debug(f"Centres of mass: {centres_of_mass}")
373
- centre_of_mass = (
374
- None
375
- if len(centres_of_mass) == 0 # type: ignore
376
- else centres_of_mass[0] - np.array([0.5, 0.5, 0.5]) # type: ignore
377
- )
378
- LOGGER.debug(f"Adjusted top centring result: {centre_of_mass}")
379
- bbox_sizes = yield from bps.rd(zocalo.bbox_sizes, default_value=[]) # type: ignore
380
- LOGGER.debug(f"Bounding box sizes: {centres_of_mass}")
381
- bbox_size = None if len(bbox_sizes) == 0 else bbox_sizes[0] # type: ignore
382
- LOGGER.debug(f"Top bbox size: {bbox_size}")
383
- return centre_of_mass, bbox_size
351
+ ) -> Generator[Msg, Any, Sequence[XrcResult]]:
352
+ """A plan that will return the raw zocalo results, ranked in descending order according to the sort key.
353
+ Returns empty list in the event no results found."""
354
+ LOGGER.info("Retrieving raw zocalo processing results")
355
+ com = yield from bps.rd(zocalo.centre_of_mass, default_value=[]) # type: ignore
356
+ max_voxel = yield from bps.rd(zocalo.max_voxel, default_value=[]) # type: ignore
357
+ max_count = yield from bps.rd(zocalo.max_count, default_value=[]) # type: ignore
358
+ n_voxels = yield from bps.rd(zocalo.n_voxels, default_value=[]) # type: ignore
359
+ total_count = yield from bps.rd(zocalo.total_count, default_value=[]) # type: ignore
360
+ bounding_box = yield from bps.rd(zocalo.bounding_box, default_value=[]) # type: ignore
361
+ return [
362
+ _corrected_xrc_result(
363
+ XrcResult(
364
+ centre_of_mass=com.tolist(),
365
+ max_voxel=mv.tolist(),
366
+ max_count=int(mc),
367
+ n_voxels=int(n),
368
+ total_count=int(tc),
369
+ bounding_box=bb.tolist(),
370
+ )
371
+ )
372
+ for com, mv, mc, n, tc, bb in zip(
373
+ com, max_voxel, max_count, n_voxels, total_count, bounding_box, strict=True
374
+ )
375
+ ]
376
+
377
+
378
+ def get_processing_results_from_event(
379
+ device_name: str, doc: dict
380
+ ) -> Sequence[XrcResult]:
381
+ """
382
+ Decode an event document into the corresponding x-ray centring results
383
+
384
+ Args:
385
+ doc A bluesky event document containing the signals read from the ZocaloResults
386
+ device_name The device name prefix to prepend to the document keys
387
+
388
+ Returns:
389
+ The list of XrcResults decoded from the event document
390
+ """
391
+ results_keys = get_annotations(XrcResult).keys()
392
+ results_dict = {k: doc["data"][f"{device_name}-{k}"] for k in results_keys}
393
+ results_values = [results_dict[k].tolist() for k in results_keys]
394
+
395
+ def create_result(*argv):
396
+ kwargs = dict(zip(results_keys, argv, strict=False))
397
+ return XrcResult(**kwargs)
398
+
399
+ return list(map(create_result, *results_values))
@@ -1,9 +1,9 @@
1
1
  from bluesky import plan_stubs as bps
2
2
  from bluesky import preprocessors as bpp
3
- from bluesky.utils import make_decorator
3
+ from bluesky.utils import MsgGenerator, make_decorator
4
4
 
5
5
  from dodal.common.beamlines import beamline_utils
6
- from dodal.common.types import MsgGenerator, UpdatingPathProvider
6
+ from dodal.common.types import UpdatingPathProvider
7
7
 
8
8
  DATA_SESSION = "data_session"
9
9
  DATA_GROUPS = "data_groups"
@@ -1,21 +1,21 @@
1
1
  import uuid
2
2
  from collections.abc import Generator
3
- from typing import Any, TypeVar
3
+ from typing import Any, TypeVar, cast
4
4
 
5
5
  from bluesky import plan_stubs as bps
6
6
  from bluesky.preprocessors import finalize_wrapper, pchain
7
- from bluesky.utils import Msg, make_decorator
7
+ from bluesky.utils import Msg, MsgGenerator, make_decorator
8
8
  from ophyd_async.core import Device
9
9
  from ophyd_async.epics.motor import Motor
10
10
 
11
- from dodal.common import MsgGenerator
11
+ from dodal.utils import MovableReadable
12
12
 
13
- AnyDevice = TypeVar("AnyDevice", bound=Device)
13
+ MovableReadableDevice = TypeVar("MovableReadableDevice", bound=MovableReadable)
14
14
 
15
15
 
16
16
  class MoveTooLarge(Exception):
17
17
  def __init__(
18
- self, axis: Device, maximum_move: float, position: float, *args: object
18
+ self, axis: MovableReadable, maximum_move: float, position: float, *args: object
19
19
  ) -> None:
20
20
  self.axis = axis
21
21
  self.maximum_move = maximum_move
@@ -24,10 +24,10 @@ class MoveTooLarge(Exception):
24
24
 
25
25
 
26
26
  def _check_and_cache_values(
27
- devices_and_positions: dict[AnyDevice, float],
27
+ devices_and_positions: dict[MovableReadableDevice, float],
28
28
  smallest_move: float,
29
29
  maximum_move: float,
30
- ) -> Generator[Msg, Any, dict[AnyDevice, float]]:
30
+ ) -> Generator[Msg, Any, dict[MovableReadableDevice, float]]:
31
31
  """Caches the positions of all Motors on specified device if they are within
32
32
  smallest_move of home_position. Throws MoveTooLarge if they are outside maximum_move
33
33
  of the home_position
@@ -51,7 +51,9 @@ def home_and_reset_wrapper(
51
51
  wait_for_all: bool = True,
52
52
  ) -> MsgGenerator:
53
53
  home_positions = {
54
- axis: 0.0 for _, axis in device.children() if isinstance(axis, Motor)
54
+ cast(MovableReadable, axis): 0.0
55
+ for _, axis in device.children()
56
+ if isinstance(axis, Motor)
55
57
  }
56
58
  return move_and_reset_wrapper(
57
59
  plan, home_positions, smallest_move, maximum_move, group, wait_for_all
@@ -60,7 +62,7 @@ def home_and_reset_wrapper(
60
62
 
61
63
  def move_and_reset_wrapper(
62
64
  plan: MsgGenerator,
63
- device_and_positions: dict[AnyDevice, float],
65
+ device_and_positions: dict[MovableReadable, float],
64
66
  smallest_move: float,
65
67
  maximum_move: float,
66
68
  group: str | None = None,
dodal/utils.py CHANGED
@@ -13,8 +13,10 @@ from os import environ
13
13
  from types import ModuleType
14
14
  from typing import (
15
15
  Any,
16
+ Protocol,
16
17
  TypeGuard,
17
18
  TypeVar,
19
+ runtime_checkable,
18
20
  )
19
21
 
20
22
  from bluesky.protocols import (
@@ -62,6 +64,11 @@ BLUESKY_PROTOCOLS = [
62
64
  Triggerable,
63
65
  ]
64
66
 
67
+
68
+ @runtime_checkable
69
+ class MovableReadable(Movable, Readable, Protocol): ...
70
+
71
+
65
72
  AnyDevice: TypeAlias = OphydV1Device | OphydV2Device
66
73
  V1DeviceFactory: TypeAlias = Callable[..., OphydV1Device]
67
74
  V2DeviceFactory: TypeAlias = Callable[..., OphydV2Device]
@@ -72,6 +79,10 @@ def get_beamline_name(default: str) -> str:
72
79
  return environ.get("BEAMLINE") or default
73
80
 
74
81
 
82
+ def is_test_mode() -> bool:
83
+ return environ.get("DODAL_TEST_MODE") == "true"
84
+
85
+
75
86
  def get_hostname() -> str:
76
87
  return socket.gethostname().split(".")[0]
77
88
 
@@ -1,136 +0,0 @@
1
- dodal/__init__.py,sha256=v-rRiDOgZ3sQSMQKq0vgUQZvpeOkoHFXissAx6Ktg84,61
2
- dodal/__main__.py,sha256=kP2S2RPitnOWpNGokjZ1Yq-1umOtp5sNOZk2B3tBPLM,111
3
- dodal/_version.py,sha256=LSm0nkFA2tiEbj_K2UaSqjWn-14u8icXCZ6ghuRODjM,413
4
- dodal/adsim.py,sha256=OW2dcS7ciD4Yq9WFw4PN_c5Bwccrmu7R-zr-u6ZCbQM,497
5
- dodal/cli.py,sha256=_crmaHchxphSW8eEJB58_XZIeK82aiUv9bV7tpz-LpA,2122
6
- dodal/log.py,sha256=0to7CRsbzbgVfAAfKRAMhsaUuKqF2-7CGdQc-z8Uhno,9499
7
- dodal/utils.py,sha256=zlHPQjJOYeEvdC-UHPRvuTZaLt4hG6o9x2Vm4eHFBDU,11851
8
- dodal/beamline_specific_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- dodal/beamline_specific_utils/i03.py,sha256=eM6ZWZzpL0JYNBff8LhOnwFoZTJ5PDCY2XWI7ZKdtFY,276
10
- dodal/beamlines/README.md,sha256=K9MkL_GomxlsoTB7Mz-_dJA5NNSbmCfMiutchGg3C8o,404
11
- dodal/beamlines/__init__.py,sha256=CD0Dz2H1adLsqY4H3-_QxTdODPZD6mquMfsep5W5s0Q,3076
12
- dodal/beamlines/b01_1.py,sha256=nH1CzeGXc9kAZBxISsuQF33On9FuWkwFriGKfU8Qs5g,2176
13
- dodal/beamlines/i03.py,sha256=8Lra4u1kLjWUoboxuSx6Po92OymRaKaJjM9ERr9zeUI,17004
14
- dodal/beamlines/i04.py,sha256=pRVNIBaUn3oIgbxInCgBUwLqHtPirxf0fKfTfx4RcJ8,13877
15
- dodal/beamlines/i04_1.py,sha256=KDxSUQNhIs_NFiRaLY-Jiory0DeN7Y0ErvGuoTrwCDU,4731
16
- dodal/beamlines/i13_1.py,sha256=csXHrdwUh4sXTmb4X6ZiiSS_XxRkNShsVoBMxYI6rG0,1833
17
- dodal/beamlines/i20_1.py,sha256=MaPgONHqpoZuBtkiKEzYtViJnKBM2_ekeP4OdbmuXHE,1158
18
- dodal/beamlines/i22.py,sha256=YWTz2PjOMTEO7n3QRfrCerIEUMHd6JTHsd2dYe_4F7c,9915
19
- dodal/beamlines/i23.py,sha256=2j5qLoqE_hg9ETHqNkOVu7LLkVB8qalgXeORnVYKN_I,1075
20
- dodal/beamlines/i24.py,sha256=1XVCNWbzowQB6CWpJGSLp9Ih0zypktIzHxb64h-Xj6Y,6583
21
- dodal/beamlines/p38.py,sha256=mCDjRVpY6AIFIAAYCWe-jGABHadFwfJB7poa-dGMU6s,7940
22
- dodal/beamlines/p45.py,sha256=N4SDTIFok3uMqb37higZHMr3xRjxItsT4ib_KacKKAE,2935
23
- dodal/beamlines/p99.py,sha256=mHMYi1M_jgSB9SrOPadxvPuMrxG8LmJOYtU0Iw6fnIQ,1708
24
- dodal/beamlines/training_rig.py,sha256=yagMEQruA1iTOeQCNpux-6xOtkBuB-hhGvAJwQ5c9bg,1846
25
- dodal/common/__init__.py,sha256=ZC4ICKUDB0BDxRaVy8nmqclVmDBne-dPtk6UJsoFq6I,258
26
- dodal/common/coordination.py,sha256=OxIjDiO1-9A9KESRPFtzwkvvQlavbgA5RHemlbubBPg,1168
27
- dodal/common/maths.py,sha256=K9x7iL3xXLtWYTV-xlFHDNSTIL9a2UP3Ws7wr6Dm2rQ,1803
28
- dodal/common/signal_utils.py,sha256=OsVJFntyTOHVEjhw27ZSp1e8SpKR2BhqdY1kzG6sago,1774
29
- dodal/common/types.py,sha256=r7Oxcw4lIGi-mvBWc1TF4LDB45q7N4IawNgOMhPohK8,621
30
- dodal/common/udc_directory_provider.py,sha256=H-9f6uSVGuA8jyiErPi8ikCw1JDrhRAJv-qPpN-HwJk,2379
31
- dodal/common/visit.py,sha256=2UbbCmgOjZWSCxFzE9RYiTJhA_IoVOegma-Jv-PJqps,5787
32
- dodal/common/beamlines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- dodal/common/beamlines/beamline_parameters.py,sha256=oIPHooqu5vTAwfqZutsKbzwdi9nvFF8568Mz7jrK5rI,3618
34
- dodal/common/beamlines/beamline_utils.py,sha256=rL-XgqAbaZF2FJDFj8OHSbvzCxSwzCUGMfTUWT5qOXs,4422
35
- dodal/common/beamlines/device_helpers.py,sha256=s79js7no9k8JMfG7NvdmFomSP5m5VDQ6th_Hsbx1znA,939
36
- dodal/devices/CTAB.py,sha256=MoExneblYUHg9Va8vAVx_p_Vw_HnqbhkzxxrX7Ic_wo,2000
37
- dodal/devices/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- dodal/devices/adsim.py,sha256=dMU0TKIuiODHYFHQOH4_5UvB8iJtaJEtjqaEDGjcU-w,311
39
- dodal/devices/aperture.py,sha256=BLaroQ3n8yd7uZyacJ3KvDWZH8yhA_sJc8b49QMKg9o,585
40
- dodal/devices/aperturescatterguard.py,sha256=KW4ERvfMpUadixJlzCVU6oRvLqLm6pFvsldruplAHc4,8404
41
- dodal/devices/attenuator.py,sha256=viK1iccNekX6ZvR_ZmSwj5JdM1j2B8pcTg8qWDdmzhQ,2584
42
- dodal/devices/backlight.py,sha256=mOnptopsVOsT8JUIX_siDRgJ73CQPz_bm0Eb7oA81wc,1607
43
- dodal/devices/cryostream.py,sha256=CpNA2HGhN_PXkL9eqH_yAPsDxyOLIiehlUxEoNmXJVg,668
44
- dodal/devices/dcm.py,sha256=eZNMGjLM56Ll0siU14XomB77W_grLIdxIrMOQNmYFG8,1609
45
- dodal/devices/eiger.py,sha256=sR-Fr97Y0lzzq57fFOUTwUZw5E7asoj36A1JR1QUkLI,13985
46
- dodal/devices/eiger_odin.py,sha256=tDpEhOUY02YManYAMRI3TwSDDa3uITBxI0JHevaK7Rk,7010
47
- dodal/devices/fast_grid_scan.py,sha256=WQGeKR-82fbnY4zUD_MQBsQyJgyIiuRpJK5nn_mfR1E,11969
48
- dodal/devices/fluorescence_detector_motion.py,sha256=5IcyaVHXa9TXLFlLB0tfpQ1_ThgIRJNaFNw_uj6ahCA,501
49
- dodal/devices/flux.py,sha256=RtPStHw7Mad0igVKntKWVZfuZn2clokVJqH14HLix6M,198
50
- dodal/devices/focusing_mirror.py,sha256=-jq2uqBfDjSgRVrV3-sqswPAND72cagBUQVvzd04diw,5901
51
- dodal/devices/hutch_shutter.py,sha256=_-hR3SJHM05YHV_fEtc0VYOLamYnpVGDE56AwJGJS48,3320
52
- dodal/devices/ipin.py,sha256=qsf8E3xrJYNDwzsacNLCCp3gaqsadqmN1b-Fvou8y8k,420
53
- dodal/devices/linkam3.py,sha256=3oYwPtaKSPvLKEat8m7tuhE4Wizz8mg8HMrEWPCYxn0,3820
54
- dodal/devices/logging_ophyd_device.py,sha256=dUVE-XhWA56WUXez0mrc4sf322CXY3MVLreTycO5j_A,668
55
- dodal/devices/motors.py,sha256=dYa9T6FDMTbr8GvTb-lXtk3v4QEqAWRuGmHIO20fazQ,1039
56
- dodal/devices/p45.py,sha256=jzBW2fGRhIbGzSRs5Fgupxro6aqE611n1RTcrTTG-yY,1047
57
- dodal/devices/robot.py,sha256=yzRq-77fVrlhxaIqeORJLGkDHzGgLrHsFYTxmkG-b0w,5343
58
- dodal/devices/s4_slit_gaps.py,sha256=j3kgF9WfGFaU9xdUuiAh-QqI5u_vhiAftaDVINt91SM,243
59
- dodal/devices/scatterguard.py,sha256=jx03in9QgaThWxD4t1S8_Llent2kWrn_hThJ9KkUWTk,330
60
- dodal/devices/scintillator.py,sha256=PlD6cnJ39PTB_e7QrRspPliLYE4kL_K7ziJURzuxgdA,365
61
- dodal/devices/slits.py,sha256=uOyVmbgeygiP6e5Z9t5zMPXLuVEWFfYg9GB3ZU76Tug,600
62
- dodal/devices/smargon.py,sha256=hX-tCftKumxk67eS5-_gQRmYOrjSyQ4s3mMJsTRuvCk,4706
63
- dodal/devices/status.py,sha256=hVrJS1yooQo6PRumRACoIEh-SKBUKxvBlQl-MtLFUMQ,327
64
- dodal/devices/synchrotron.py,sha256=QtTufJA_fCaBawHougSc7nxwu240oX46_y0P-4qIW8o,1960
65
- dodal/devices/tetramm.py,sha256=EgtaExJBZWZC6lWgUEg0RcWQYmSKwRm20KjTZyhCjBk,8439
66
- dodal/devices/thawer.py,sha256=Gq-3f__KJUM6_Ds9OVxpZ5jC447HywJxQGXen6L33Lk,1616
67
- dodal/devices/turbo_slit.py,sha256=B6SPXqviMnG-U4PnUF1BdTO0LBKmTuwAUKRbxMiNJXo,1125
68
- dodal/devices/undulator.py,sha256=udwAodxYM9XgtsQGH2PDBA6ehtel5dAFkjsK13nKp6Q,5160
69
- dodal/devices/undulator_dcm.py,sha256=5hn3UZeu4CYXmfUVSdIxjrcIpStgeA1S744p0iIFp4I,2725
70
- dodal/devices/webcam.py,sha256=EqdzUBov5wMCULzzkfnCfD-5TQMZFQLp-2nlDHezmPs,2332
71
- dodal/devices/xbpm_feedback.py,sha256=-1wbnahJ_oSljQR0Sjiwn3mytVP-VwsAy0a_YPjPM0Y,1168
72
- dodal/devices/zebra.py,sha256=iTHkKv8EP-gkr0Cl2gR9yxt2qTHT2Q4etS67Rshf83k,9327
73
- dodal/devices/zebra_controlled_shutter.py,sha256=w2ISASJ_sb3dbQGi63Yuj3ymTkjX73aSl_ZTYs8TyaI,1860
74
- dodal/devices/areadetector/__init__.py,sha256=8IwLxuZMW0MOJpJp_ZDdlaE20hrtsH_PXWGaKgMiYs4,240
75
- dodal/devices/areadetector/adaravis.py,sha256=Cqw_Mzrp_zODFxQ2LZBJzHp_DsZ6_dAITkZz8gYz_0w,3797
76
- dodal/devices/areadetector/adsim.py,sha256=cIc9PRbKnftBk7Ut8d8CU_TVrin8EwcKHObP2n9VxWM,1876
77
- dodal/devices/areadetector/adutils.py,sha256=4axFR3wtn-K-sjMVJyfTcu-8g35odf2cY8mTKv1gS-o,3093
78
- dodal/devices/areadetector/plugins/MJPG.py,sha256=XztHFB1e7qHeZORYxvPgHfDMfkpXGKvfQYmej_hGVVc,4934
79
- dodal/devices/detector/__init__.py,sha256=-RdACL3tzc3lLArWOoGNje48UUlv2fElOmGOz9yOuO0,317
80
- dodal/devices/detector/det_dim_constants.py,sha256=LNrVMd0DbFEcnyNFmXosCP-VYaZ71Ajuv6inwo4Mg3U,2299
81
- dodal/devices/detector/det_dist_to_beam_converter.py,sha256=7keoqZYfvgayePVx97lHYpcFRTJnQOfAk_PYP4EZTZQ,1951
82
- dodal/devices/detector/det_resolution.py,sha256=aQkKp24LpRGiwzPAQM3wLVa4ANw32HdrKc2kftHfKQA,3253
83
- dodal/devices/detector/detector.py,sha256=syzkl52kGaMINXCXEviFuYPbgNatm5tioVPDmjgro8s,4768
84
- dodal/devices/detector/detector_motion.py,sha256=LjHNi9FcDSZoriQYrFde8fEmwCGccFgSHPtcxivix4g,1628
85
- dodal/devices/i03/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
- dodal/devices/i04/transfocator.py,sha256=uieByXIj0JRbmvMB_om5NOAEbEJkzfkCD24bl2aEo1g,3154
87
- dodal/devices/i20_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
88
- dodal/devices/i22/dcm.py,sha256=YXf4iH4-dNTfm0NPUgrbn1iLP24id4pR8xLsvLc_iWg,6290
89
- dodal/devices/i22/fswitch.py,sha256=AlyZ_RdbXoMHrG2-sddNOUyLl3vkBdduXVnFL_rMgLo,3046
90
- dodal/devices/i22/nxsas.py,sha256=a8oJXl5uhkh9zcb9rSZmVooU-SplzzO3EsAaHJZRfrQ,6086
91
- dodal/devices/i24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
- dodal/devices/i24/aperture.py,sha256=bbT4ts5jfrjrOxG199RGDxIYmzVyv1k0ZlZcmS6kEzU,849
93
- dodal/devices/i24/beamstop.py,sha256=GpqSaHlyZfcUfaCgvQRjhDgNdGsrOwV_NqG9JLfcusY,1233
94
- dodal/devices/i24/dcm.py,sha256=nP2qymTy5TrOu078XOY7h1TEwVfcgli5lTyxmwsG4O8,1990
95
- dodal/devices/i24/dual_backlight.py,sha256=Th-RKr28aFxE8LCT_mdN9KkRIVw0BHLGKkI0ienfRZU,2049
96
- dodal/devices/i24/i24_detector_motion.py,sha256=_HgdsZqFYY0tKqUgMzViHaPEUFXL3WlXXioGvDehRUw,364
97
- dodal/devices/i24/i24_vgonio.py,sha256=Igqs7687z6lyhGVeJEDtDmPachYxU48MUH2BF0RpK9Q,461
98
- dodal/devices/i24/pmac.py,sha256=qug40tz00vjvmQox3W6GrEcorriEeGkNyP5m4u5CVHo,7201
99
- dodal/devices/oav/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
- dodal/devices/oav/grid_overlay.py,sha256=kYs4sCvmo7yG75HQtptuI8jPzM7dR4fSqnOGL0D5j6g,5338
101
- dodal/devices/oav/microns_for_zoom_levels.json,sha256=kJTkbu2v6_Ccc_cDy7FRTX-gRhXxfYskjVqwBCZIqCQ,1209
102
- dodal/devices/oav/oav_calculations.py,sha256=wt71vFcyQrr98FvX8oyUM2n5vmKi3K7PyOTuWp0gq5w,1665
103
- dodal/devices/oav/oav_detector.py,sha256=ZlVzFo01hYi2qITMP6k6TbTE9-7c8veMDoDcTiyU6kc,3178
104
- dodal/devices/oav/oav_errors.py,sha256=cc4mGnaTiAc5WIlOt_BIYOc7CRSkrCdnBaavfAJ0pXY,754
105
- dodal/devices/oav/oav_parameters.py,sha256=rI0kRl8B-N2mw91yYf1lEQVn0hkBQCPU7jvljr5ZNpk,8235
106
- dodal/devices/oav/oav_to_redis_forwarder.py,sha256=3I8Vk1Qx04aVftXb7VVkHUVHweGGUyuLFdmaasmb_Qk,4606
107
- dodal/devices/oav/utils.py,sha256=OyE4h4eq_jg9bEq5DfcjCU-wfSJifO2-PIsrDbsa0NE,3020
108
- dodal/devices/oav/pin_image_recognition/__init__.py,sha256=l5IsWMDZDw3-jk0DkGpiw_BzqyfVYRonlfX6Je1ZPR0,6446
109
- dodal/devices/oav/pin_image_recognition/manual_test.py,sha256=h1Rto6ZDCB3jWhjSy9N8ECxRN583iYDJr9LxrTJ8kfE,903
110
- dodal/devices/oav/pin_image_recognition/utils.py,sha256=L9ypluYqeOFoS7gQuws-vTNc8LqaKl2ZIDNeQ2JaNpg,8592
111
- dodal/devices/p99/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
- dodal/devices/p99/sample_stage.py,sha256=kvwKCDUmXqcoXfIbAENtqm3Hi2cHP7dZIPQgQT6hsXw,1140
113
- dodal/devices/training_rig/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
- dodal/devices/training_rig/sample_stage.py,sha256=jktTp837ij8wor5LidE3AajCk95L7DebJotMlO7QwTE,355
115
- dodal/devices/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
116
- dodal/devices/util/adjuster_plans.py,sha256=g4HTpji3XhIhpWvyDLyCYYLGOSE7uNpDeQHfh8259hE,878
117
- dodal/devices/util/epics_util.py,sha256=R0_I9HEZ2l19BZaTpevPqT3p3kp5GZCfmNNmnXGfdsc,4689
118
- dodal/devices/util/lookup_tables.py,sha256=FxT2fiIjDJNOqUf_pcW0fKJmwhOUZiF8UGTFz6hWf5g,2132
119
- dodal/devices/util/motor_utils.py,sha256=pNY-aUk9LxaIWeDr5rpMS6udiB9j19wcCXkNDLp1uA0,257
120
- dodal/devices/util/save_panda.py,sha256=PHFlkerBhkkU0-o5dNEdi2P95_jD9Lk8yYgaqn9R97o,2538
121
- dodal/devices/util/test_utils.py,sha256=VrSFFGLNKOcCAsWFMZOxwhng3wGR5kV8NqqnKfj8Vuw,562
122
- dodal/devices/xspress3/xspress3.py,sha256=JTx3ppAc8GwV9K-Gfqo81iGYH_L-ONyFWiPRs9XUs-w,4661
123
- dodal/devices/xspress3/xspress3_channel.py,sha256=yJRwseLmtkW2Vv6GB8sLdOFuBn3e4c9Q8fgPacMgl5w,1638
124
- dodal/devices/zocalo/__init__.py,sha256=oPhjFB39yf2NWkGD-MMcPFnnOVZ_RtdyBt2OLYn-Xa4,505
125
- dodal/devices/zocalo/zocalo_interaction.py,sha256=y8YKMaVwfsRPBofHGGLYmYsd4QwMvm7JIPEo6wrN_Xo,3493
126
- dodal/devices/zocalo/zocalo_results.py,sha256=MStx8iK--ITff-rT3AQu_RHnqKqNGLJDVyV3ewBwaKE,14316
127
- dodal/parameters/experiment_parameter_base.py,sha256=O7JamfuJ5cYHkPf9tsHJPqn-OMHTAGouigvM1cDFehE,313
128
- dodal/plans/check_topup.py,sha256=3gyLHfHNQBCgEWuAg4QE-ONx7y2Do1vVv5HP8ss0Z1I,5371
129
- dodal/plans/data_session_metadata.py,sha256=urexZ3mA0K6VWxVW3MlrcsB1Tyi09tFvpKBlaVil7TQ,1567
130
- dodal/plans/motor_util_plans.py,sha256=JT1K4DBB66MrzNqimxFgiL6mRsj11fF7xZXOz0udEeo,4522
131
- dls_dodal-1.33.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
132
- dls_dodal-1.33.0.dist-info/METADATA,sha256=wwy8R9Z3KMfUP7WOcWSZVk7EdoYqRSPXREOqroAGALo,16574
133
- dls_dodal-1.33.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
134
- dls_dodal-1.33.0.dist-info/entry_points.txt,sha256=bycw_EKUzup_rxfCetOwcauXV4kLln_OPpPT8jEnr-I,94
135
- dls_dodal-1.33.0.dist-info/top_level.txt,sha256=xIozdmZk_wmMV4wugpq9-6eZs0vgADNUKz3j2UAwlhc,6
136
- dls_dodal-1.33.0.dist-info/RECORD,,