dls-dodal 1.29.3__py3-none-any.whl → 1.30.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.
- {dls_dodal-1.29.3.dist-info → dls_dodal-1.30.0.dist-info}/METADATA +28 -43
- dls_dodal-1.30.0.dist-info/RECORD +132 -0
- {dls_dodal-1.29.3.dist-info → dls_dodal-1.30.0.dist-info}/WHEEL +1 -1
- dls_dodal-1.30.0.dist-info/entry_points.txt +3 -0
- dodal/__init__.py +1 -4
- dodal/_version.py +2 -2
- dodal/beamlines/__init__.py +3 -1
- dodal/beamlines/i03.py +28 -23
- dodal/beamlines/i04.py +34 -12
- dodal/beamlines/i13_1.py +66 -0
- dodal/beamlines/i22.py +5 -5
- dodal/beamlines/i24.py +15 -1
- dodal/beamlines/p38.py +7 -7
- dodal/beamlines/p45.py +7 -5
- dodal/beamlines/p99.py +61 -0
- dodal/cli.py +6 -3
- dodal/common/beamlines/beamline_parameters.py +2 -2
- dodal/common/beamlines/beamline_utils.py +6 -5
- dodal/common/maths.py +1 -3
- dodal/common/types.py +2 -3
- dodal/common/udc_directory_provider.py +14 -3
- dodal/common/visit.py +2 -3
- dodal/devices/CTAB.py +22 -17
- dodal/devices/aperturescatterguard.py +114 -136
- dodal/devices/areadetector/adaravis.py +8 -6
- dodal/devices/areadetector/adsim.py +2 -3
- dodal/devices/areadetector/adutils.py +20 -12
- dodal/devices/areadetector/plugins/MJPG.py +0 -4
- dodal/devices/attenuator.py +4 -4
- dodal/devices/cryostream.py +19 -7
- dodal/devices/detector/__init__.py +13 -2
- dodal/devices/detector/det_dim_constants.py +2 -2
- dodal/devices/detector/det_dist_to_beam_converter.py +1 -1
- dodal/devices/detector/detector.py +8 -7
- dodal/devices/detector/detector_motion.py +38 -31
- dodal/devices/eiger.py +23 -23
- dodal/devices/eiger_odin.py +12 -13
- dodal/devices/fast_grid_scan.py +4 -3
- dodal/devices/fluorescence_detector_motion.py +13 -4
- dodal/devices/focusing_mirror.py +66 -66
- dodal/devices/hutch_shutter.py +4 -4
- dodal/devices/i22/dcm.py +4 -3
- dodal/devices/i22/fswitch.py +4 -4
- dodal/devices/i22/nxsas.py +23 -32
- dodal/devices/i24/dcm.py +42 -0
- dodal/devices/i24/pmac.py +47 -8
- dodal/devices/ipin.py +7 -4
- dodal/devices/linkam3.py +11 -5
- dodal/devices/logging_ophyd_device.py +1 -1
- dodal/devices/motors.py +31 -5
- dodal/devices/oav/grid_overlay.py +1 -0
- dodal/devices/oav/microns_for_zoom_levels.json +1 -1
- dodal/devices/oav/oav_detector.py +2 -0
- dodal/devices/oav/oav_parameters.py +18 -10
- dodal/devices/oav/oav_to_redis_forwarder.py +100 -0
- dodal/devices/oav/pin_image_recognition/__init__.py +19 -17
- dodal/devices/oav/pin_image_recognition/utils.py +5 -6
- dodal/devices/oav/utils.py +3 -17
- dodal/devices/p99/__init__.py +0 -0
- dodal/devices/p99/sample_stage.py +43 -0
- dodal/devices/robot.py +30 -18
- dodal/devices/scintillator.py +8 -5
- dodal/devices/smargon.py +3 -3
- dodal/devices/status.py +2 -31
- dodal/devices/tetramm.py +4 -4
- dodal/devices/thawer.py +5 -3
- dodal/devices/undulator_dcm.py +6 -8
- dodal/devices/util/adjuster_plans.py +2 -2
- dodal/devices/util/epics_util.py +6 -8
- dodal/devices/util/lookup_tables.py +2 -3
- dodal/devices/util/save_panda.py +87 -0
- dodal/devices/util/test_utils.py +17 -0
- dodal/devices/webcam.py +3 -8
- dodal/devices/xbpm_feedback.py +0 -23
- dodal/devices/zebra.py +10 -10
- dodal/devices/zebra_controlled_shutter.py +3 -3
- dodal/devices/zocalo/zocalo_interaction.py +10 -2
- dodal/devices/zocalo/zocalo_results.py +31 -18
- dodal/log.py +14 -5
- dodal/plans/data_session_metadata.py +1 -0
- dodal/plans/motor_util_plans.py +117 -0
- dodal/utils.py +74 -26
- dls_dodal-1.29.3.dist-info/RECORD +0 -124
- dls_dodal-1.29.3.dist-info/entry_points.txt +0 -2
- dodal/devices/qbpm1.py +0 -8
- {dls_dodal-1.29.3.dist-info → dls_dodal-1.30.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.29.3.dist-info → dls_dodal-1.30.0.dist-info}/top_level.txt +0 -0
- /dodal/devices/i24/{I24_detector_motion.py → i24_detector_motion.py} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import dataclasses
|
|
2
2
|
import getpass
|
|
3
|
+
import os
|
|
3
4
|
import socket
|
|
4
5
|
from dataclasses import dataclass
|
|
5
6
|
|
|
@@ -37,6 +38,12 @@ class ZocaloStartInfo:
|
|
|
37
38
|
message_index: int
|
|
38
39
|
|
|
39
40
|
|
|
41
|
+
def _get_zocalo_headers() -> tuple[str, str]:
|
|
42
|
+
user = os.environ.get("ZOCALO_GO_USER", getpass.getuser())
|
|
43
|
+
hostname = os.environ.get("ZOCALO_GO_HOSTNAME", socket.gethostname())
|
|
44
|
+
return user, hostname
|
|
45
|
+
|
|
46
|
+
|
|
40
47
|
class ZocaloTrigger:
|
|
41
48
|
"""This class just sends 'run_start' and 'run_end' messages to zocalo, it is
|
|
42
49
|
intended to be used in bluesky callback classes. To get results from zocalo back
|
|
@@ -55,9 +62,10 @@ class ZocaloTrigger:
|
|
|
55
62
|
"recipes": ["mimas"],
|
|
56
63
|
"parameters": parameters,
|
|
57
64
|
}
|
|
65
|
+
user, hostname = _get_zocalo_headers()
|
|
58
66
|
header = {
|
|
59
|
-
"zocalo.go.user":
|
|
60
|
-
"zocalo.go.host":
|
|
67
|
+
"zocalo.go.user": user,
|
|
68
|
+
"zocalo.go.host": hostname,
|
|
61
69
|
}
|
|
62
70
|
transport.send("processing_recipe", message, headers=header)
|
|
63
71
|
finally:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from collections import OrderedDict
|
|
3
|
+
from collections.abc import Generator, Sequence
|
|
3
4
|
from enum import Enum
|
|
4
5
|
from queue import Empty, Queue
|
|
5
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, TypedDict
|
|
6
7
|
|
|
7
8
|
import bluesky.plan_stubs as bps
|
|
8
9
|
import numpy as np
|
|
@@ -10,7 +11,7 @@ import workflows.recipe
|
|
|
10
11
|
import workflows.transport
|
|
11
12
|
from bluesky.protocols import Descriptor, Triggerable
|
|
12
13
|
from numpy.typing import NDArray
|
|
13
|
-
from ophyd_async.core import StandardReadable, soft_signal_r_and_setter
|
|
14
|
+
from ophyd_async.core import HintedSignal, StandardReadable, soft_signal_r_and_setter
|
|
14
15
|
from ophyd_async.core.async_status import AsyncStatus
|
|
15
16
|
from workflows.transport.common_transport import CommonTransport
|
|
16
17
|
|
|
@@ -79,34 +80,41 @@ class ZocaloResults(StandardReadable, Triggerable):
|
|
|
79
80
|
self._raw_results_received: Queue = Queue()
|
|
80
81
|
self.transport: CommonTransport | None = None
|
|
81
82
|
|
|
82
|
-
self.results,
|
|
83
|
-
|
|
83
|
+
self.results, self._results_setter = soft_signal_r_and_setter(
|
|
84
|
+
list[XrcResult], name="results"
|
|
85
|
+
)
|
|
86
|
+
self.centres_of_mass, self._com_setter = soft_signal_r_and_setter(
|
|
84
87
|
NDArray[np.uint64], name="centres_of_mass"
|
|
85
88
|
)
|
|
86
|
-
self.bbox_sizes,
|
|
89
|
+
self.bbox_sizes, self._bbox_setter = soft_signal_r_and_setter(
|
|
87
90
|
NDArray[np.uint64], "bbox_sizes", self.name
|
|
88
91
|
)
|
|
89
|
-
self.ispyb_dcid,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
self.ispyb_dcid, self._ispyb_dcid_setter = soft_signal_r_and_setter(
|
|
93
|
+
int, name="ispyb_dcid"
|
|
94
|
+
)
|
|
95
|
+
self.ispyb_dcgid, self._ispyb_dcgid_setter = soft_signal_r_and_setter(
|
|
96
|
+
int, name="ispyb_dcgid"
|
|
97
|
+
)
|
|
98
|
+
self.add_readables(
|
|
99
|
+
[
|
|
93
100
|
self.results,
|
|
94
101
|
self.centres_of_mass,
|
|
95
102
|
self.bbox_sizes,
|
|
96
103
|
self.ispyb_dcid,
|
|
97
104
|
self.ispyb_dcgid,
|
|
98
|
-
]
|
|
105
|
+
],
|
|
106
|
+
wrapper=HintedSignal,
|
|
99
107
|
)
|
|
100
108
|
super().__init__(name)
|
|
101
109
|
|
|
102
110
|
async def _put_results(self, results: Sequence[XrcResult], ispyb_ids):
|
|
103
|
-
|
|
111
|
+
self._results_setter(list(results))
|
|
104
112
|
centres_of_mass = np.array([r["centre_of_mass"] for r in results])
|
|
105
113
|
bbox_sizes = np.array([bbox_size(r) for r in results])
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
114
|
+
self._com_setter(centres_of_mass)
|
|
115
|
+
self._bbox_setter(bbox_sizes)
|
|
116
|
+
self._ispyb_dcid_setter(ispyb_ids["dcid"])
|
|
117
|
+
self._ispyb_dcgid_setter(ispyb_ids["dcgid"])
|
|
110
118
|
|
|
111
119
|
def _clear_old_results(self):
|
|
112
120
|
LOGGER.info("Clearing queue")
|
|
@@ -120,7 +128,12 @@ class ZocaloResults(StandardReadable, Triggerable):
|
|
|
120
128
|
before triggering processing for the experiment"""
|
|
121
129
|
|
|
122
130
|
LOGGER.info("Subscribing to results queue")
|
|
123
|
-
|
|
131
|
+
try:
|
|
132
|
+
self._subscribe_to_results()
|
|
133
|
+
except Exception as e:
|
|
134
|
+
print(f"GOT {e}")
|
|
135
|
+
raise
|
|
136
|
+
|
|
124
137
|
await asyncio.sleep(CLEAR_QUEUE_WAIT_S)
|
|
125
138
|
self._clear_old_results()
|
|
126
139
|
|
|
@@ -152,7 +165,7 @@ class ZocaloResults(StandardReadable, Triggerable):
|
|
|
152
165
|
)
|
|
153
166
|
|
|
154
167
|
raw_results = self._raw_results_received.get(timeout=self.timeout_s)
|
|
155
|
-
LOGGER.info(f"Zocalo: found {len(raw_results)} crystals.")
|
|
168
|
+
LOGGER.info(f"Zocalo: found {len(raw_results['results'])} crystals.")
|
|
156
169
|
# Sort from strongest to weakest in case of multiple crystals
|
|
157
170
|
await self._put_results(
|
|
158
171
|
sorted(
|
|
@@ -242,7 +255,7 @@ class ZocaloResults(StandardReadable, Triggerable):
|
|
|
242
255
|
|
|
243
256
|
def get_processing_result(
|
|
244
257
|
zocalo: ZocaloResults,
|
|
245
|
-
) -> Generator[Any, Any,
|
|
258
|
+
) -> Generator[Any, Any, tuple[np.ndarray, np.ndarray] | tuple[None, None]]:
|
|
246
259
|
"""A minimal plan which will extract the top ranked xray centre and crystal bounding
|
|
247
260
|
box size from the zocalo results. Returns (None, None) if no crystals were found."""
|
|
248
261
|
|
dodal/log.py
CHANGED
|
@@ -6,7 +6,7 @@ from logging import Logger, StreamHandler
|
|
|
6
6
|
from logging.handlers import TimedRotatingFileHandler
|
|
7
7
|
from os import environ
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import TypedDict
|
|
10
10
|
|
|
11
11
|
from bluesky.log import logger as bluesky_logger
|
|
12
12
|
from graypy import GELFTCPHandler
|
|
@@ -37,11 +37,14 @@ class CircularMemoryHandler(logging.Handler):
|
|
|
37
37
|
that always contains the last {capacity} number of messages, this is only flushed
|
|
38
38
|
when a log of specific {flushLevel} comes in. On flush this buffer is then passed to
|
|
39
39
|
the {target} handler.
|
|
40
|
+
|
|
41
|
+
The CircularMemoryHandler becomes the owner of the target handler which will be closed
|
|
42
|
+
on close of this handler.
|
|
40
43
|
"""
|
|
41
44
|
|
|
42
45
|
def __init__(self, capacity, flushLevel=logging.ERROR, target=None):
|
|
43
46
|
logging.Handler.__init__(self)
|
|
44
|
-
self.buffer:
|
|
47
|
+
self.buffer: deque[logging.LogRecord] = deque(maxlen=capacity)
|
|
45
48
|
self.flushLevel = flushLevel
|
|
46
49
|
self.target = target
|
|
47
50
|
|
|
@@ -66,6 +69,12 @@ class CircularMemoryHandler(logging.Handler):
|
|
|
66
69
|
self.acquire()
|
|
67
70
|
try:
|
|
68
71
|
self.buffer.clear()
|
|
72
|
+
if self.target:
|
|
73
|
+
self.target.acquire()
|
|
74
|
+
try:
|
|
75
|
+
self.target.close()
|
|
76
|
+
finally:
|
|
77
|
+
self.target.release()
|
|
69
78
|
self.target = None
|
|
70
79
|
logging.Handler.close(self)
|
|
71
80
|
finally:
|
|
@@ -121,7 +130,7 @@ def set_up_graylog_handler(logger: Logger, host: str, port: int):
|
|
|
121
130
|
def set_up_INFO_file_handler(logger, path: Path, filename: str):
|
|
122
131
|
"""Set up a file handler for the logger, at INFO level, which will keep 30 days
|
|
123
132
|
of logs, rotating once per day. Creates the directory if necessary."""
|
|
124
|
-
print(f"Logging to {path/filename}")
|
|
133
|
+
print(f"Logging to INFO file handler {path/filename}")
|
|
125
134
|
path.mkdir(parents=True, exist_ok=True)
|
|
126
135
|
file_handler = TimedRotatingFileHandler(
|
|
127
136
|
filename=path / filename, when="MIDNIGHT", backupCount=INFO_LOG_DAYS
|
|
@@ -137,8 +146,8 @@ def set_up_DEBUG_memory_handler(
|
|
|
137
146
|
"""Set up a Memory handler which holds 200k lines, and writes them to an hourly
|
|
138
147
|
log file when it sees a message of severity ERROR. Creates the directory if
|
|
139
148
|
necessary"""
|
|
140
|
-
print(f"Logging to {path/filename}")
|
|
141
149
|
debug_path = path / "debug"
|
|
150
|
+
print(f"Logging to DEBUG handler {debug_path/filename}")
|
|
142
151
|
debug_path.mkdir(parents=True, exist_ok=True)
|
|
143
152
|
file_handler = TimedRotatingFileHandler(
|
|
144
153
|
filename=debug_path / filename, when="H", backupCount=DEBUG_LOG_FILES_TO_KEEP
|
|
@@ -240,7 +249,7 @@ def get_logging_file_path() -> Path:
|
|
|
240
249
|
|
|
241
250
|
def get_graylog_configuration(
|
|
242
251
|
dev_mode: bool, graylog_port: int | None = None
|
|
243
|
-
) ->
|
|
252
|
+
) -> tuple[str, int]:
|
|
244
253
|
"""Get the host and port for the graylog handler.
|
|
245
254
|
|
|
246
255
|
If running in dev mode, this switches to localhost. Otherwise it publishes to the
|
|
@@ -37,6 +37,7 @@ def attach_data_session_metadata_wrapper(
|
|
|
37
37
|
directory_info: DirectoryInfo = provider()
|
|
38
38
|
# https://github.com/DiamondLightSource/dodal/issues/452
|
|
39
39
|
# As part of 452, write each dataCollection into their own folder, then can use resource_dir directly
|
|
40
|
+
assert directory_info.prefix is not None
|
|
40
41
|
data_session = directory_info.prefix.removesuffix("-")
|
|
41
42
|
yield from bpp.inject_md_wrapper(plan, md={DATA_SESSION: data_session})
|
|
42
43
|
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from collections.abc import Generator
|
|
3
|
+
from typing import Any, TypeVar
|
|
4
|
+
|
|
5
|
+
from bluesky import plan_stubs as bps
|
|
6
|
+
from bluesky.preprocessors import finalize_wrapper, pchain
|
|
7
|
+
from bluesky.utils import Msg, make_decorator
|
|
8
|
+
from ophyd_async.core import Device
|
|
9
|
+
from ophyd_async.epics.motion import Motor
|
|
10
|
+
|
|
11
|
+
from dodal.common import MsgGenerator
|
|
12
|
+
|
|
13
|
+
AnyDevice = TypeVar("AnyDevice", bound=Device)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MoveTooLarge(Exception):
|
|
17
|
+
def __init__(
|
|
18
|
+
self, axis: Device, maximum_move: float, position: float, *args: object
|
|
19
|
+
) -> None:
|
|
20
|
+
self.axis = axis
|
|
21
|
+
self.maximum_move = maximum_move
|
|
22
|
+
self.position = position
|
|
23
|
+
super().__init__(*args)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _check_and_cache_values(
|
|
27
|
+
devices_and_positions: dict[AnyDevice, float],
|
|
28
|
+
smallest_move: float,
|
|
29
|
+
maximum_move: float,
|
|
30
|
+
) -> Generator[Msg, Any, dict[AnyDevice, float]]:
|
|
31
|
+
"""Caches the positions of all Motors on specified device if they are within
|
|
32
|
+
smallest_move of home_position. Throws MoveTooLarge if they are outside maximum_move
|
|
33
|
+
of the home_position
|
|
34
|
+
"""
|
|
35
|
+
positions = {}
|
|
36
|
+
for axis, new_position in devices_and_positions.items():
|
|
37
|
+
position = yield from bps.rd(axis)
|
|
38
|
+
if abs(position - new_position) > maximum_move:
|
|
39
|
+
raise MoveTooLarge(axis, maximum_move, position)
|
|
40
|
+
if abs(position - new_position) > smallest_move:
|
|
41
|
+
positions[axis] = position
|
|
42
|
+
return positions
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def home_and_reset_wrapper(
|
|
46
|
+
plan: MsgGenerator,
|
|
47
|
+
device: Device,
|
|
48
|
+
smallest_move: float,
|
|
49
|
+
maximum_move: float,
|
|
50
|
+
group: str | None = None,
|
|
51
|
+
wait_for_all: bool = True,
|
|
52
|
+
) -> MsgGenerator:
|
|
53
|
+
home_positions = {
|
|
54
|
+
axis: 0.0 for _, axis in device.children() if isinstance(axis, Motor)
|
|
55
|
+
}
|
|
56
|
+
return move_and_reset_wrapper(
|
|
57
|
+
plan, home_positions, smallest_move, maximum_move, group, wait_for_all
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def move_and_reset_wrapper(
|
|
62
|
+
plan: MsgGenerator,
|
|
63
|
+
device_and_positions: dict[AnyDevice, float],
|
|
64
|
+
smallest_move: float,
|
|
65
|
+
maximum_move: float,
|
|
66
|
+
group: str | None = None,
|
|
67
|
+
wait_for_all: bool = True,
|
|
68
|
+
) -> MsgGenerator:
|
|
69
|
+
"""Wrapper that does the following:
|
|
70
|
+
1. Caches the positions of all Motors on device
|
|
71
|
+
2. Throws a MoveTooLarge exception if any positions are maximum_move away from home_position
|
|
72
|
+
2. Moves any motor that is more than smallest_move away from the home_position to home_position
|
|
73
|
+
3. Runs the specified plan
|
|
74
|
+
4. Moves all motors back to their cached positions
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
plan (Callable[[], MsgGenerator]): The plan to move between homing and returning to the cache
|
|
78
|
+
device (Device): The device to move. All Motors in the device will be cached and moved
|
|
79
|
+
smallest_move (float): The smallest move that we care about doing the home and cache for.
|
|
80
|
+
Useful for not wearing out motors if you have large tolerances
|
|
81
|
+
maximum_move (float): If any Motor starts this far from the home an exception is raised
|
|
82
|
+
and no moves occur
|
|
83
|
+
home_position (float): The position to move every motor to after caching
|
|
84
|
+
group (str, optional): If set the home move will be done using the home-{group}
|
|
85
|
+
group and the reset to cache done using reset-{group}
|
|
86
|
+
wait_for_all (bool, optional): If true the home and reset to cache will be waited
|
|
87
|
+
on. If false it is left up to the caller to wait on
|
|
88
|
+
them. Defaults to True.
|
|
89
|
+
"""
|
|
90
|
+
initial_positions = yield from _check_and_cache_values(
|
|
91
|
+
device_and_positions, smallest_move, maximum_move
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def move_to_home():
|
|
95
|
+
home_group = f"home-{group if group else str(uuid.uuid4())[:6]}"
|
|
96
|
+
for axis, position in device_and_positions.items():
|
|
97
|
+
if axis in initial_positions.keys():
|
|
98
|
+
yield from bps.abs_set(axis, position, group=home_group)
|
|
99
|
+
if wait_for_all:
|
|
100
|
+
yield from bps.wait(home_group)
|
|
101
|
+
|
|
102
|
+
def return_to_initial_position():
|
|
103
|
+
reset_group = f"reset-{group if group else str(uuid.uuid4())[:6]}"
|
|
104
|
+
for axis, position in initial_positions.items():
|
|
105
|
+
yield from bps.abs_set(axis, position, group=reset_group)
|
|
106
|
+
if wait_for_all:
|
|
107
|
+
yield from bps.wait(reset_group)
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
yield from finalize_wrapper(
|
|
111
|
+
pchain(move_to_home(), plan),
|
|
112
|
+
return_to_initial_position(),
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
home_and_reset_decorator = make_decorator(home_and_reset_wrapper)
|
dodal/utils.py
CHANGED
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import re
|
|
5
5
|
import socket
|
|
6
6
|
import string
|
|
7
|
+
from collections.abc import Callable, Iterable, Mapping
|
|
7
8
|
from dataclasses import dataclass
|
|
8
9
|
from functools import wraps
|
|
9
10
|
from importlib import import_module
|
|
@@ -12,13 +13,6 @@ from os import environ
|
|
|
12
13
|
from types import ModuleType
|
|
13
14
|
from typing import (
|
|
14
15
|
Any,
|
|
15
|
-
Callable,
|
|
16
|
-
Dict,
|
|
17
|
-
Iterable,
|
|
18
|
-
List,
|
|
19
|
-
Mapping,
|
|
20
|
-
Tuple,
|
|
21
|
-
Type,
|
|
22
16
|
TypeVar,
|
|
23
17
|
)
|
|
24
18
|
|
|
@@ -46,7 +40,7 @@ import dodal.log
|
|
|
46
40
|
try:
|
|
47
41
|
from typing import TypeAlias
|
|
48
42
|
except ImportError:
|
|
49
|
-
from
|
|
43
|
+
from typing import TypeAlias
|
|
50
44
|
|
|
51
45
|
|
|
52
46
|
#: Protocols defining interface to hardware
|
|
@@ -108,9 +102,35 @@ def skip_device(precondition=lambda: True):
|
|
|
108
102
|
return decorator
|
|
109
103
|
|
|
110
104
|
|
|
105
|
+
def make_device(
|
|
106
|
+
module: str | ModuleType,
|
|
107
|
+
device_name: str,
|
|
108
|
+
**kwargs,
|
|
109
|
+
) -> dict[str, AnyDevice]:
|
|
110
|
+
"""Make a single named device and its dependencies from the given beamline module.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
module (str | ModuleType): The module to make devices from.
|
|
114
|
+
device_name: Name of the device to construct
|
|
115
|
+
**kwargs: Arguments passed on to every device factory
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
dict[str, AnyDevice]: A dict mapping device names to the constructed devices
|
|
119
|
+
"""
|
|
120
|
+
if isinstance(module, str):
|
|
121
|
+
module = import_module(module)
|
|
122
|
+
|
|
123
|
+
device_collector = {}
|
|
124
|
+
factories = collect_factories(module)
|
|
125
|
+
device_collector[device_name] = _make_one_device(
|
|
126
|
+
module, device_name, device_collector, factories, **kwargs
|
|
127
|
+
)
|
|
128
|
+
return device_collector
|
|
129
|
+
|
|
130
|
+
|
|
111
131
|
def make_all_devices(
|
|
112
132
|
module: str | ModuleType | None = None, include_skipped: bool = False, **kwargs
|
|
113
|
-
) ->
|
|
133
|
+
) -> tuple[dict[str, AnyDevice], dict[str, Exception]]:
|
|
114
134
|
"""Makes all devices in the given beamline module.
|
|
115
135
|
|
|
116
136
|
In cases of device interdependencies it ensures a device is created before any which
|
|
@@ -129,7 +149,7 @@ def make_all_devices(
|
|
|
129
149
|
if isinstance(module, str) or module is None:
|
|
130
150
|
module = import_module(module or __name__)
|
|
131
151
|
factories = collect_factories(module, include_skipped)
|
|
132
|
-
devices:
|
|
152
|
+
devices: tuple[dict[str, AnyDevice], dict[str, Exception]] = invoke_factories(
|
|
133
153
|
factories, **kwargs
|
|
134
154
|
)
|
|
135
155
|
|
|
@@ -139,7 +159,7 @@ def make_all_devices(
|
|
|
139
159
|
def invoke_factories(
|
|
140
160
|
factories: Mapping[str, AnyDeviceFactory],
|
|
141
161
|
**kwargs,
|
|
142
|
-
) ->
|
|
162
|
+
) -> tuple[dict[str, AnyDevice], dict[str, Exception]]:
|
|
143
163
|
"""Call device factory functions in the correct order to resolve dependencies.
|
|
144
164
|
Inspect function signatures to work out dependencies and execute functions in
|
|
145
165
|
correct order.
|
|
@@ -259,15 +279,13 @@ def is_any_device_factory(func: Callable) -> bool:
|
|
|
259
279
|
return is_v1_device_factory(func) or is_v2_device_factory(func)
|
|
260
280
|
|
|
261
281
|
|
|
262
|
-
def is_v2_device_type(obj:
|
|
263
|
-
return inspect.isclass(obj) and
|
|
282
|
+
def is_v2_device_type(obj: type[Any]) -> bool:
|
|
283
|
+
return inspect.isclass(obj) and isinstance(obj, OphydV2Device)
|
|
264
284
|
|
|
265
285
|
|
|
266
|
-
def is_v1_device_type(obj:
|
|
286
|
+
def is_v1_device_type(obj: type[Any]) -> bool:
|
|
267
287
|
is_class = inspect.isclass(obj)
|
|
268
|
-
follows_protocols = any(
|
|
269
|
-
(isinstance(obj, protocol) for protocol in BLUESKY_PROTOCOLS)
|
|
270
|
-
)
|
|
288
|
+
follows_protocols = any(isinstance(obj, protocol) for protocol in BLUESKY_PROTOCOLS)
|
|
271
289
|
return is_class and follows_protocols and not is_v2_device_type(obj)
|
|
272
290
|
|
|
273
291
|
|
|
@@ -292,13 +310,11 @@ def get_beamline_based_on_environment_variable() -> ModuleType:
|
|
|
292
310
|
or any(c not in valid_characters for c in beamline)
|
|
293
311
|
):
|
|
294
312
|
raise ValueError(
|
|
295
|
-
"Invalid BEAMLINE variable - module name is not a permissible python module name, got '{}'"
|
|
296
|
-
beamline
|
|
297
|
-
)
|
|
313
|
+
f"Invalid BEAMLINE variable - module name is not a permissible python module name, got '{beamline}'"
|
|
298
314
|
)
|
|
299
315
|
|
|
300
316
|
try:
|
|
301
|
-
return importlib.import_module("dodal.beamlines.{}"
|
|
317
|
+
return importlib.import_module(f"dodal.beamlines.{beamline}")
|
|
302
318
|
except ImportError as e:
|
|
303
319
|
raise ValueError(
|
|
304
320
|
f"Failed to import beamline-specific dodal module 'dodal.beamlines.{beamline}'."
|
|
@@ -306,7 +322,7 @@ def get_beamline_based_on_environment_variable() -> ModuleType:
|
|
|
306
322
|
) from e
|
|
307
323
|
|
|
308
324
|
|
|
309
|
-
def _find_next_run_number_from_files(file_names:
|
|
325
|
+
def _find_next_run_number_from_files(file_names: list[str]) -> int:
|
|
310
326
|
valid_numbers = []
|
|
311
327
|
|
|
312
328
|
for file_name in file_names:
|
|
@@ -322,12 +338,44 @@ def _find_next_run_number_from_files(file_names: List[str]) -> int:
|
|
|
322
338
|
return max(valid_numbers) + 1 if valid_numbers else 1
|
|
323
339
|
|
|
324
340
|
|
|
325
|
-
def get_run_number(directory: str) -> int:
|
|
326
|
-
"""Looks at the numbers coming from all nexus files with the format
|
|
327
|
-
or 1 if there are
|
|
328
|
-
|
|
341
|
+
def get_run_number(directory: str, prefix: str = "") -> int:
|
|
342
|
+
"""Looks at the numbers coming from all nexus files with the format
|
|
343
|
+
"{prefix}_(any number}.nxs", and returns the highest number + 1, or 1 if there are
|
|
344
|
+
no matching numbers found. If no prefix is given, considers all files in the dir."""
|
|
345
|
+
nexus_file_names = [
|
|
346
|
+
file
|
|
347
|
+
for file in os.listdir(directory)
|
|
348
|
+
if file.endswith(".nxs") and file.startswith(prefix)
|
|
349
|
+
]
|
|
329
350
|
|
|
330
351
|
if len(nexus_file_names) == 0:
|
|
331
352
|
return 1
|
|
332
353
|
else:
|
|
333
354
|
return _find_next_run_number_from_files(nexus_file_names)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _make_one_device(
|
|
358
|
+
module: ModuleType,
|
|
359
|
+
device_name: str,
|
|
360
|
+
devices: dict[str, AnyDevice],
|
|
361
|
+
factories: dict[str, AnyDeviceFactory],
|
|
362
|
+
**kwargs,
|
|
363
|
+
) -> AnyDevice:
|
|
364
|
+
factory = factories.get(device_name)
|
|
365
|
+
if not factory:
|
|
366
|
+
raise ValueError(f"Unable to find factory for {device_name}")
|
|
367
|
+
|
|
368
|
+
dependencies = list(extract_dependencies(factories, device_name))
|
|
369
|
+
for dependency_name in dependencies:
|
|
370
|
+
if dependency_name not in devices:
|
|
371
|
+
try:
|
|
372
|
+
devices[dependency_name] = _make_one_device(
|
|
373
|
+
module, dependency_name, devices, factories, **kwargs
|
|
374
|
+
)
|
|
375
|
+
except Exception as e:
|
|
376
|
+
raise RuntimeError(
|
|
377
|
+
f"Unable to construct device {dependency_name}"
|
|
378
|
+
) from e
|
|
379
|
+
|
|
380
|
+
params = {name: devices[name] for name in dependencies}
|
|
381
|
+
return factory(**params, **kwargs)
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
dodal/__init__.py,sha256=y-VRpfiX-Lm5nchB9N0VfMy_6dwFqVxpSn5SiAQql9I,114
|
|
2
|
-
dodal/__main__.py,sha256=kP2S2RPitnOWpNGokjZ1Yq-1umOtp5sNOZk2B3tBPLM,111
|
|
3
|
-
dodal/_version.py,sha256=MFlkKJKBPRaG5o-APjK5uWe00dvrrzhYEjQcU5M7B2I,413
|
|
4
|
-
dodal/adsim.py,sha256=OW2dcS7ciD4Yq9WFw4PN_c5Bwccrmu7R-zr-u6ZCbQM,497
|
|
5
|
-
dodal/cli.py,sha256=z0UBESrNrq6Kq4rttp4uHcwS1fnOnRkKBRDHSriPpGY,2058
|
|
6
|
-
dodal/log.py,sha256=dfo1rfYrGG8oIm2HkNxaa_ldVs4vJKtgWSoKe1Z_Xno,8533
|
|
7
|
-
dodal/utils.py,sha256=aH-W94t6NFOoGHZ7awbUKY8_k7qIYDourCFs3MKIjjA,10024
|
|
8
|
-
dodal/beamline_specific_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
dodal/beamline_specific_utils/i03.py,sha256=Ixe1anFQl-kwRJubmQx28TIW4Zw8qDxpElNNNapWQHI,396
|
|
10
|
-
dodal/beamlines/README.md,sha256=K9MkL_GomxlsoTB7Mz-_dJA5NNSbmCfMiutchGg3C8o,404
|
|
11
|
-
dodal/beamlines/__init__.py,sha256=U0dQYFEUloCdQOs24zyfpPTncJXOO4cDcfHSevVOAw4,2890
|
|
12
|
-
dodal/beamlines/i03.py,sha256=J-4GawTxAhrYDQZh87n11L9ehTgObEQ1Lz2PueXCWbc,16892
|
|
13
|
-
dodal/beamlines/i04.py,sha256=JOyNcUnC3wva4no2MHKp6b8gOKAcQXL_c4cBo7oneVs,13034
|
|
14
|
-
dodal/beamlines/i04_1.py,sha256=KDxSUQNhIs_NFiRaLY-Jiory0DeN7Y0ErvGuoTrwCDU,4731
|
|
15
|
-
dodal/beamlines/i20_1.py,sha256=MaPgONHqpoZuBtkiKEzYtViJnKBM2_ekeP4OdbmuXHE,1158
|
|
16
|
-
dodal/beamlines/i22.py,sha256=3VFdA4Wc7O40-64lwUtUBIN23fH4JVNbLKJ1JLjy9as,9870
|
|
17
|
-
dodal/beamlines/i23.py,sha256=2j5qLoqE_hg9ETHqNkOVu7LLkVB8qalgXeORnVYKN_I,1075
|
|
18
|
-
dodal/beamlines/i24.py,sha256=dCMQGcBZ6ADZ6_rEDFcV2BPHGKBC9iVFvfxewxVts4k,6111
|
|
19
|
-
dodal/beamlines/p38.py,sha256=TC78u4GwEnj6X0r5cnHhqNdBbbDRnh8lY8pEucBZjEU,8006
|
|
20
|
-
dodal/beamlines/p45.py,sha256=TNIkC-SBfj0ayZtlLLXW9xCSi5CzJkO8XpAMIo8fjao,2957
|
|
21
|
-
dodal/common/__init__.py,sha256=ZC4ICKUDB0BDxRaVy8nmqclVmDBne-dPtk6UJsoFq6I,258
|
|
22
|
-
dodal/common/coordination.py,sha256=OxIjDiO1-9A9KESRPFtzwkvvQlavbgA5RHemlbubBPg,1168
|
|
23
|
-
dodal/common/maths.py,sha256=JRSBhbMzwlicKp1_Bsfu9gA79JJA_Dgq9EpbExFH65M,1829
|
|
24
|
-
dodal/common/types.py,sha256=M0gZs9F7--gREF8VYJn-Y1Mt9mIEgp1aLY3oUpUkSno,546
|
|
25
|
-
dodal/common/udc_directory_provider.py,sha256=zNlt_VgdAlyBtVN7neTHk_0tWBbI4pPUL7q9WQOzXvo,1260
|
|
26
|
-
dodal/common/visit.py,sha256=MhrFbLptMG0Wvd2nHubBwQ44qAzoP4Bf4_z_-wO8rh0,6063
|
|
27
|
-
dodal/common/beamlines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
-
dodal/common/beamlines/beamline_parameters.py,sha256=N22dtDLw3Hlo7EUmGxe4qFGcu7OnldwCz_mU7yK2rd0,3577
|
|
29
|
-
dodal/common/beamlines/beamline_utils.py,sha256=AgmH9wpnFQ4DHAA7_Yo0COa2piX2ksFxukFt2_600kA,4488
|
|
30
|
-
dodal/common/beamlines/device_helpers.py,sha256=s79js7no9k8JMfG7NvdmFomSP5m5VDQ6th_Hsbx1znA,939
|
|
31
|
-
dodal/devices/CTAB.py,sha256=_MfL_KH4uDPxq_RuHFEZ9HVXOpUnQb5be3csoz9DdAs,1630
|
|
32
|
-
dodal/devices/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
-
dodal/devices/adsim.py,sha256=dMU0TKIuiODHYFHQOH4_5UvB8iJtaJEtjqaEDGjcU-w,311
|
|
34
|
-
dodal/devices/aperture.py,sha256=0MtTzKMDZ5DVAz0DE0kXI0M76VCp0y9vFsrMggEMpxk,586
|
|
35
|
-
dodal/devices/aperturescatterguard.py,sha256=2JJsEPJGJHrI0ztv1cSaP7H5T6qdzDfUcN-VEQ39B8o,11012
|
|
36
|
-
dodal/devices/attenuator.py,sha256=OD7fElTIMHWk7ZopPqEu29lionm7WwgC0-Kvl8vBIb0,2599
|
|
37
|
-
dodal/devices/backlight.py,sha256=vsNGZB4C_mVMafllvJlOTghsfv6UqALMKUMLXu3WZ5k,1115
|
|
38
|
-
dodal/devices/beamstop.py,sha256=8L3qhlk-3ZBOp10xK1i8qZqYTGOXX1mVF1MgXoN0dfg,215
|
|
39
|
-
dodal/devices/cryostream.py,sha256=6MU4rXIOL33C-8F3DVfAtv0ZnwiysTtawjkeePd5IrQ,332
|
|
40
|
-
dodal/devices/dcm.py,sha256=vfyGYDzfSwTiNqlzkfNjkrL-Q1hNVSgJddvJ5Un_lvg,1610
|
|
41
|
-
dodal/devices/eiger.py,sha256=NE4tHdqgUZpUxJLQbd5lLUIHZcpeotppexJGlDNByzM,13868
|
|
42
|
-
dodal/devices/eiger_odin.py,sha256=U5Byb7uNwDdNscBRp7yBYQrsjKrKXl2l5WdSpL09lAw,6980
|
|
43
|
-
dodal/devices/fast_grid_scan.py,sha256=BEj96j78r60JPPJoOMP-XXG-_9yURFTuu-pp2LcqQmY,12452
|
|
44
|
-
dodal/devices/fluorescence_detector_motion.py,sha256=RrXfPmJzWnAjcjp9u0AnJEfjvWPMKburVTySB2hxYbw,181
|
|
45
|
-
dodal/devices/flux.py,sha256=RtPStHw7Mad0igVKntKWVZfuZn2clokVJqH14HLix6M,198
|
|
46
|
-
dodal/devices/focusing_mirror.py,sha256=aRqBkE3OgaXpH6lP3v1VbSYgHsMMbSsPPXzeyAGf_Pg,6435
|
|
47
|
-
dodal/devices/hutch_shutter.py,sha256=nZ3gRbYIVJsXLlpZMWT4UEYUFFQP1MwMe8Oy304QsqE,3360
|
|
48
|
-
dodal/devices/ipin.py,sha256=OGMXwAE4KDDonZRPFkUmR9Vsk6X4Ox-hEvPT5drP-mQ,208
|
|
49
|
-
dodal/devices/linkam3.py,sha256=TPhiQ1D9i_HIlKHAlfnVfX7H6aPOAeXPEJLdmvwdKWQ,3776
|
|
50
|
-
dodal/devices/logging_ophyd_device.py,sha256=xw4lbyqq5_ehESGterVEfubJsBiJTWvBp5b9k62gSkg,666
|
|
51
|
-
dodal/devices/motors.py,sha256=16ID2jFJ35h6ZrFp76nJG_oQg6uDrupgcbvcbmjlc7c,300
|
|
52
|
-
dodal/devices/p45.py,sha256=jzBW2fGRhIbGzSRs5Fgupxro6aqE611n1RTcrTTG-yY,1047
|
|
53
|
-
dodal/devices/qbpm1.py,sha256=OY7-WbdxMiLGUK8Z57ezwqSXbHxoPP-y3GvBgj9kgMA,220
|
|
54
|
-
dodal/devices/robot.py,sha256=5WQ9kF5m8xhHhipBycsycDV0-_2IBNBkcwuSWP-9-1I,4337
|
|
55
|
-
dodal/devices/s4_slit_gaps.py,sha256=j3kgF9WfGFaU9xdUuiAh-QqI5u_vhiAftaDVINt91SM,243
|
|
56
|
-
dodal/devices/scatterguard.py,sha256=0qnvhoo3RjLsrxVgIoDJpryqunlgMVgaTsoyKRC2g4Y,331
|
|
57
|
-
dodal/devices/scintillator.py,sha256=4Dej1a6HRom9GRwTDsaTKGfvloP20POUqIeHqsI8-R8,184
|
|
58
|
-
dodal/devices/slits.py,sha256=URru9VN2N19KqeUPDZaBmyKYn0_JJiE0Vko4sZpfsl8,601
|
|
59
|
-
dodal/devices/smargon.py,sha256=Ds8QFqK3ljbTxalqkQ6clpArj4u4hu9d4vrt97Fzdf4,4693
|
|
60
|
-
dodal/devices/status.py,sha256=TuUGidZ4Ar-WCRc_sX0wn58DmL6brj1pMr8rNF5Z6VU,1198
|
|
61
|
-
dodal/devices/synchrotron.py,sha256=QtTufJA_fCaBawHougSc7nxwu240oX46_y0P-4qIW8o,1960
|
|
62
|
-
dodal/devices/tetramm.py,sha256=XriN-zBFVnHxhnTbphSPIZcxEbdWBTbw2g_ulUBl4bw,8538
|
|
63
|
-
dodal/devices/thawer.py,sha256=hIdZOzCNloY7CtSvdE2gk4vCMMoOtaIA4dPH_k0OwFg,1527
|
|
64
|
-
dodal/devices/turbo_slit.py,sha256=W3ZRIqDhq4iMhr5GcIiWvl2U1GaPtGanqkL7upQOZTY,1132
|
|
65
|
-
dodal/devices/undulator.py,sha256=kn84MQpuBHtQj7H7HeBoAYKXu5buGKvTgs3tf2gdEdw,2074
|
|
66
|
-
dodal/devices/undulator_dcm.py,sha256=TC9fO55r1YIG_88PPbGGtzfjcRJcaoC2ny51JiDOEX4,5199
|
|
67
|
-
dodal/devices/webcam.py,sha256=FXYcxQdOOCRIMAf8jMWlDVAhSEs4ycGCnoODvHb-apM,1554
|
|
68
|
-
dodal/devices/xbpm_feedback.py,sha256=8QHYKHo9ksZo30olbFM-tHpCHcJRFozgHKVJijv3Gck,1986
|
|
69
|
-
dodal/devices/zebra.py,sha256=9Zkq5I3-gcP6qfDBnPEAtFU4QJ-VJyp7cHvB79ZfLHk,9186
|
|
70
|
-
dodal/devices/zebra_controlled_shutter.py,sha256=MqX4KE6w0FliZRDBltswcLCNSsp6vQrD_iBY640IljI,1094
|
|
71
|
-
dodal/devices/areadetector/__init__.py,sha256=8IwLxuZMW0MOJpJp_ZDdlaE20hrtsH_PXWGaKgMiYs4,240
|
|
72
|
-
dodal/devices/areadetector/adaravis.py,sha256=pwbmmnakarjhD59XoyAIXJdakS-nqDG09Xmwq17AVw4,3787
|
|
73
|
-
dodal/devices/areadetector/adsim.py,sha256=3U7kS93RM3Xeh-XWKjeuw5jXbIGWAbrs59LfxtvB7OU,1907
|
|
74
|
-
dodal/devices/areadetector/adutils.py,sha256=JIx1_sYlehpLtEXcwOEuzVoMplsLdKVW7OWv5eiJqgE,2576
|
|
75
|
-
dodal/devices/areadetector/plugins/MJPG.py,sha256=pLuEZiRGgCwJM1ONA5jdetGLo6O0OVhvmcVkkYtPeR8,4159
|
|
76
|
-
dodal/devices/detector/__init__.py,sha256=XEwjopgTtBq93RRuFthVVVI9DT1jUvpOJzWOHantJpU,104
|
|
77
|
-
dodal/devices/detector/det_dim_constants.py,sha256=MZ4w2nsTKzj4eN7yGsSs1pqKWIuU4vc6UzcSll02uWg,2305
|
|
78
|
-
dodal/devices/detector/det_dist_to_beam_converter.py,sha256=f6JFp-eEB2v8NzZg27UrN0VDP5CMjRnaPU6BTA7_n_s,1937
|
|
79
|
-
dodal/devices/detector/det_resolution.py,sha256=aQkKp24LpRGiwzPAQM3wLVa4ANw32HdrKc2kftHfKQA,3253
|
|
80
|
-
dodal/devices/detector/detector.py,sha256=arP27DbrgOjYZhE6Ibp9kDBglfmqZpPBk53S5ItsrvE,4756
|
|
81
|
-
dodal/devices/detector/detector_motion.py,sha256=REREva2kyPcIzOZmahN9rT0jDSuUbV0qUDl4IcBnutA,1221
|
|
82
|
-
dodal/devices/i03/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
|
-
dodal/devices/i04/transfocator.py,sha256=uieByXIj0JRbmvMB_om5NOAEbEJkzfkCD24bl2aEo1g,3154
|
|
84
|
-
dodal/devices/i20_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
85
|
-
dodal/devices/i22/dcm.py,sha256=Kzyd_qFg8KVhRsgfTQVOpghESE8yIOgACKa0Fv9NaZI,6270
|
|
86
|
-
dodal/devices/i22/fswitch.py,sha256=AdYtnkCBuhivyJGZqelg_7sjB2pHN7vl1JTtlO4vHo4,3061
|
|
87
|
-
dodal/devices/i22/nxsas.py,sha256=ky7v9UZ1UQFsm5hI0wD9OXG-fTKFLj2wJjB7wADxKpw,5655
|
|
88
|
-
dodal/devices/i24/I24_detector_motion.py,sha256=Joqr1orgeNvRS7n01bjaO-4Yu4obb8fnKaWHQfjPX14,365
|
|
89
|
-
dodal/devices/i24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
90
|
-
dodal/devices/i24/aperture.py,sha256=kKfHli5oKp-j-qZhZoXTRK81SAUNyhpI6VRvtw0SkZA,850
|
|
91
|
-
dodal/devices/i24/beamstop.py,sha256=28hQowTvgN5Zw38tkDh32h2ceyN-2GE8bAaGPvDOt5U,1234
|
|
92
|
-
dodal/devices/i24/dual_backlight.py,sha256=Th-RKr28aFxE8LCT_mdN9KkRIVw0BHLGKkI0ienfRZU,2049
|
|
93
|
-
dodal/devices/i24/i24_vgonio.py,sha256=Igqs7687z6lyhGVeJEDtDmPachYxU48MUH2BF0RpK9Q,461
|
|
94
|
-
dodal/devices/i24/pmac.py,sha256=pN54myYvzqPl7iW0Vsp59J1EiV_gtn0xQGwbsKJpiYE,3876
|
|
95
|
-
dodal/devices/oav/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
96
|
-
dodal/devices/oav/grid_overlay.py,sha256=FRtjcFd420XY8MEQ9sWedL0i4pK-KUJOSxh2C5zM3PA,5232
|
|
97
|
-
dodal/devices/oav/microns_for_zoom_levels.json,sha256=5PA71RzldFTp0eTUGPmov0MjxHe583mzvfor5f3thXI,1208
|
|
98
|
-
dodal/devices/oav/oav_calculations.py,sha256=wt71vFcyQrr98FvX8oyUM2n5vmKi3K7PyOTuWp0gq5w,1665
|
|
99
|
-
dodal/devices/oav/oav_detector.py,sha256=JtzRdFQVXUdVK4Qyd9knDhsfkK6tsXoD_rIWDpLdpD4,3654
|
|
100
|
-
dodal/devices/oav/oav_errors.py,sha256=cc4mGnaTiAc5WIlOt_BIYOc7CRSkrCdnBaavfAJ0pXY,754
|
|
101
|
-
dodal/devices/oav/oav_parameters.py,sha256=4XybkhKeG7IEjPRfx0PVM9KNenuyN0rAGWBZG7H3zvQ,7941
|
|
102
|
-
dodal/devices/oav/utils.py,sha256=zbUDvNETDoCtclj5jNzxz1XBt5mQlWBbxUrhRP7pZrU,3663
|
|
103
|
-
dodal/devices/oav/pin_image_recognition/__init__.py,sha256=qEX3BRnrcP1BLZD-f_smHiMMPLJPkWQZQbIWTbW25JA,6499
|
|
104
|
-
dodal/devices/oav/pin_image_recognition/manual_test.py,sha256=h1Rto6ZDCB3jWhjSy9N8ECxRN583iYDJr9LxrTJ8kfE,903
|
|
105
|
-
dodal/devices/oav/pin_image_recognition/utils.py,sha256=-7-Zs-331UVTq_AZrfdF-zwZdmMn7eitTkBSqnBrxnk,8620
|
|
106
|
-
dodal/devices/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
107
|
-
dodal/devices/util/adjuster_plans.py,sha256=2AYaywQP_LbA2KJ6Op3cok8GoRtj696utrSSDfaJtBY,875
|
|
108
|
-
dodal/devices/util/epics_util.py,sha256=eQr-ImBnADpBL_6XWr3_q9yuMe55Lu0h3j9L1fG4Jws,4714
|
|
109
|
-
dodal/devices/util/lookup_tables.py,sha256=Up-0BlARt79TIEM76SkDyn9LtTFLxPUcaEPZv6D6bws,2141
|
|
110
|
-
dodal/devices/util/motor_utils.py,sha256=pNY-aUk9LxaIWeDr5rpMS6udiB9j19wcCXkNDLp1uA0,257
|
|
111
|
-
dodal/devices/xspress3/xspress3.py,sha256=29elzI3JtceryKeMWXhcP9nWl0tlSdnTZhltCitet6A,4668
|
|
112
|
-
dodal/devices/xspress3/xspress3_channel.py,sha256=yJRwseLmtkW2Vv6GB8sLdOFuBn3e4c9Q8fgPacMgl5w,1638
|
|
113
|
-
dodal/devices/zocalo/__init__.py,sha256=oPhjFB39yf2NWkGD-MMcPFnnOVZ_RtdyBt2OLYn-Xa4,505
|
|
114
|
-
dodal/devices/zocalo/zocalo_interaction.py,sha256=B6TBTDwUlluksLTwC4TiEEgfFzWLOmwgG8xM5Xd4Wik,3132
|
|
115
|
-
dodal/devices/zocalo/zocalo_results.py,sha256=U4Vk4OF-eL8w0BR-fbw3k4jyRo6G3Ywaf8NMAkjr4Hs,9658
|
|
116
|
-
dodal/parameters/experiment_parameter_base.py,sha256=O7JamfuJ5cYHkPf9tsHJPqn-OMHTAGouigvM1cDFehE,313
|
|
117
|
-
dodal/plans/check_topup.py,sha256=Pj6Eu8fa6nvoW4awrMxvzE_ftpLfYz8bN0QDLRw0Yuk,2989
|
|
118
|
-
dodal/plans/data_session_metadata.py,sha256=QNx9rb1EfGBHb21eFekIi7KjNhC0PL-SVKBCggDuNeg,1650
|
|
119
|
-
dls_dodal-1.29.3.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
120
|
-
dls_dodal-1.29.3.dist-info/METADATA,sha256=WmlVBYCSTsRn07vPGXJa_FF8x_djiThku9KSaCay3A8,16942
|
|
121
|
-
dls_dodal-1.29.3.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
|
|
122
|
-
dls_dodal-1.29.3.dist-info/entry_points.txt,sha256=wpzz9FsTiYxI8OBwLKX9V9ResLwThBSmtRMcPwII0FA,46
|
|
123
|
-
dls_dodal-1.29.3.dist-info/top_level.txt,sha256=xIozdmZk_wmMV4wugpq9-6eZs0vgADNUKz3j2UAwlhc,6
|
|
124
|
-
dls_dodal-1.29.3.dist-info/RECORD,,
|
dodal/devices/qbpm1.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|