dls-dodal 1.30.0__py3-none-any.whl → 1.31.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.30.0.dist-info → dls_dodal-1.31.0.dist-info}/METADATA +4 -4
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.0.dist-info}/RECORD +64 -62
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.0.dist-info}/WHEEL +1 -1
- dodal/_version.py +2 -2
- dodal/beamline_specific_utils/i03.py +1 -4
- dodal/beamlines/__init__.py +4 -0
- dodal/beamlines/i03.py +8 -8
- dodal/beamlines/i04.py +10 -9
- dodal/beamlines/i13_1.py +7 -7
- dodal/beamlines/i22.py +18 -18
- dodal/beamlines/p38.py +14 -14
- dodal/beamlines/p45.py +11 -11
- dodal/beamlines/training_rig.py +64 -0
- dodal/common/beamlines/beamline_parameters.py +5 -4
- dodal/common/beamlines/beamline_utils.py +9 -9
- dodal/common/types.py +4 -2
- dodal/common/udc_directory_provider.py +29 -22
- dodal/common/visit.py +59 -60
- dodal/devices/CTAB.py +1 -1
- dodal/devices/aperture.py +1 -1
- dodal/devices/aperturescatterguard.py +140 -188
- dodal/devices/areadetector/plugins/MJPG.py +2 -1
- dodal/devices/backlight.py +12 -1
- dodal/devices/dcm.py +1 -1
- dodal/devices/detector/detector.py +31 -30
- dodal/devices/detector/detector_motion.py +1 -1
- dodal/devices/fast_grid_scan.py +14 -24
- dodal/devices/focusing_mirror.py +2 -2
- dodal/devices/i22/dcm.py +1 -1
- dodal/devices/i22/fswitch.py +6 -2
- dodal/devices/i22/nxsas.py +32 -11
- dodal/devices/i24/aperture.py +1 -1
- dodal/devices/i24/beamstop.py +1 -1
- dodal/devices/i24/dcm.py +1 -1
- dodal/devices/i24/i24_detector_motion.py +1 -1
- dodal/devices/i24/pmac.py +24 -8
- dodal/devices/linkam3.py +1 -1
- dodal/devices/motors.py +1 -1
- dodal/devices/oav/oav_to_redis_forwarder.py +46 -17
- dodal/devices/robot.py +1 -2
- dodal/devices/scatterguard.py +1 -1
- dodal/devices/scintillator.py +1 -1
- dodal/devices/slits.py +1 -1
- dodal/devices/smargon.py +1 -1
- dodal/devices/tetramm.py +20 -16
- dodal/devices/training_rig/__init__.py +0 -0
- dodal/devices/training_rig/sample_stage.py +10 -0
- dodal/devices/turbo_slit.py +1 -1
- dodal/devices/undulator.py +1 -1
- dodal/devices/util/adjuster_plans.py +1 -1
- dodal/devices/util/save_panda.py +1 -1
- dodal/devices/util/test_utils.py +1 -1
- dodal/devices/xbpm_feedback.py +1 -2
- dodal/devices/xspress3/xspress3.py +1 -1
- dodal/devices/zebra.py +5 -0
- dodal/devices/zebra_controlled_shutter.py +24 -9
- dodal/devices/zocalo/zocalo_results.py +6 -2
- dodal/log.py +32 -10
- dodal/plans/check_topup.py +65 -10
- dodal/plans/data_session_metadata.py +8 -10
- dodal/plans/motor_util_plans.py +1 -1
- dodal/devices/beamstop.py +0 -8
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.30.0.dist-info → dls_dodal-1.31.0.dist-info}/top_level.txt +0 -0
dodal/beamlines/p45.py
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
-
from ophyd_async.epics.
|
|
4
|
-
from ophyd_async.panda import HDFPanda
|
|
3
|
+
from ophyd_async.epics.adaravis import AravisDetector
|
|
4
|
+
from ophyd_async.fastcs.panda import HDFPanda
|
|
5
5
|
|
|
6
6
|
from dodal.common.beamlines.beamline_utils import (
|
|
7
7
|
device_instantiation,
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
get_path_provider,
|
|
9
|
+
set_path_provider,
|
|
10
10
|
)
|
|
11
11
|
from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline
|
|
12
|
-
from dodal.common.visit import
|
|
12
|
+
from dodal.common.visit import StaticVisitPathProvider
|
|
13
13
|
from dodal.devices.p45 import Choppers, TomoStageWithStretchAndSkew
|
|
14
14
|
from dodal.log import set_beamline as set_log_beamline
|
|
15
15
|
from dodal.utils import get_beamline_name, skip_device
|
|
@@ -17,8 +17,8 @@ from dodal.utils import get_beamline_name, skip_device
|
|
|
17
17
|
BL = get_beamline_name("p45")
|
|
18
18
|
set_log_beamline(BL)
|
|
19
19
|
set_utils_beamline(BL)
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
set_path_provider(
|
|
21
|
+
StaticVisitPathProvider(
|
|
22
22
|
BL,
|
|
23
23
|
Path("/data/2024/cm37283-2/"), # latest commissioning visit
|
|
24
24
|
)
|
|
@@ -62,7 +62,7 @@ def det(
|
|
|
62
62
|
fake_with_ophyd_sim,
|
|
63
63
|
drv_suffix="DET:",
|
|
64
64
|
hdf_suffix="HDF5:",
|
|
65
|
-
|
|
65
|
+
path_provider=get_path_provider(),
|
|
66
66
|
)
|
|
67
67
|
|
|
68
68
|
|
|
@@ -79,7 +79,7 @@ def diff(
|
|
|
79
79
|
fake_with_ophyd_sim,
|
|
80
80
|
drv_suffix="DET:",
|
|
81
81
|
hdf_suffix="HDF5:",
|
|
82
|
-
|
|
82
|
+
path_provider=get_path_provider(),
|
|
83
83
|
)
|
|
84
84
|
|
|
85
85
|
|
|
@@ -97,7 +97,7 @@ def panda1(
|
|
|
97
97
|
"-MO-PANDA-01:",
|
|
98
98
|
wait_for_connection,
|
|
99
99
|
fake_with_ophyd_sim,
|
|
100
|
-
|
|
100
|
+
path_provider=get_path_provider(),
|
|
101
101
|
)
|
|
102
102
|
|
|
103
103
|
|
|
@@ -112,5 +112,5 @@ def panda2(
|
|
|
112
112
|
"-MO-PANDA-02:",
|
|
113
113
|
wait_for_connection,
|
|
114
114
|
fake_with_ophyd_sim,
|
|
115
|
-
|
|
115
|
+
path_provider=get_path_provider(),
|
|
116
116
|
)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from ophyd_async.epics.adaravis import AravisDetector
|
|
4
|
+
|
|
5
|
+
from dodal.common.beamlines.beamline_utils import (
|
|
6
|
+
device_instantiation,
|
|
7
|
+
get_path_provider,
|
|
8
|
+
set_path_provider,
|
|
9
|
+
)
|
|
10
|
+
from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline
|
|
11
|
+
from dodal.common.visit import LocalDirectoryServiceClient, StaticVisitPathProvider
|
|
12
|
+
from dodal.devices.training_rig.sample_stage import TrainingRigSampleStage
|
|
13
|
+
from dodal.log import set_beamline as set_log_beamline
|
|
14
|
+
from dodal.utils import get_beamline_name
|
|
15
|
+
|
|
16
|
+
#
|
|
17
|
+
# HTSS Training Rig
|
|
18
|
+
#
|
|
19
|
+
# A mock-beamline design that is employed at Diamond, consisting of a pair of
|
|
20
|
+
# simple motors, a GigE camera and a PandA.
|
|
21
|
+
# Since there are multiple rigs whose PVs are identical aside from the prefix,
|
|
22
|
+
# this module can be used for any rig. It should fill in the prefix automatically
|
|
23
|
+
# if the ${BEAMLINE} environment variable is correctly set. It currently defaults
|
|
24
|
+
# to p47.
|
|
25
|
+
#
|
|
26
|
+
|
|
27
|
+
BL = get_beamline_name("p47")
|
|
28
|
+
set_log_beamline(BL)
|
|
29
|
+
set_utils_beamline(BL)
|
|
30
|
+
|
|
31
|
+
set_path_provider(
|
|
32
|
+
StaticVisitPathProvider(
|
|
33
|
+
BL,
|
|
34
|
+
Path("/exports/mybeamline/data"),
|
|
35
|
+
client=LocalDirectoryServiceClient(),
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def sample_stage(
|
|
41
|
+
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
42
|
+
) -> TrainingRigSampleStage:
|
|
43
|
+
return device_instantiation(
|
|
44
|
+
TrainingRigSampleStage,
|
|
45
|
+
"sample_stage",
|
|
46
|
+
"-MO-MAP-01:STAGE:",
|
|
47
|
+
wait_for_connection,
|
|
48
|
+
fake_with_ophyd_sim,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def det(
|
|
53
|
+
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
54
|
+
) -> AravisDetector:
|
|
55
|
+
return device_instantiation(
|
|
56
|
+
AravisDetector,
|
|
57
|
+
"det",
|
|
58
|
+
"-EA-DET-01:",
|
|
59
|
+
wait_for_connection,
|
|
60
|
+
fake_with_ophyd_sim,
|
|
61
|
+
drv_suffix="DET:",
|
|
62
|
+
hdf_suffix="HDF5:",
|
|
63
|
+
path_provider=get_path_provider(),
|
|
64
|
+
)
|
|
@@ -7,7 +7,7 @@ BEAMLINE_PARAMETER_KEYWORDS = ["FB", "FULL", "deadtime"]
|
|
|
7
7
|
|
|
8
8
|
BEAMLINE_PARAMETER_PATHS = {
|
|
9
9
|
"i03": "/dls_sw/i03/software/daq_configuration/domain/beamlineParameters",
|
|
10
|
-
"i04": "/dls_sw/i04/software/gda_versions/
|
|
10
|
+
"i04": "/dls_sw/i04/software/gda_versions/gda_9_34/workspace_git/gda-mx.git/configurations/i04-config/scripts/beamlineParameters",
|
|
11
11
|
"s03": "tests/test_data/test_beamline_parameters.txt",
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -15,6 +15,9 @@ BEAMLINE_PARAMETER_PATHS = {
|
|
|
15
15
|
class GDABeamlineParameters:
|
|
16
16
|
params: dict[str, Any]
|
|
17
17
|
|
|
18
|
+
def __init__(self, params: dict[str, Any]):
|
|
19
|
+
self.params = params
|
|
20
|
+
|
|
18
21
|
def __repr__(self) -> str:
|
|
19
22
|
return repr(self.params)
|
|
20
23
|
|
|
@@ -23,7 +26,6 @@ class GDABeamlineParameters:
|
|
|
23
26
|
|
|
24
27
|
@classmethod
|
|
25
28
|
def from_lines(cls, file_name: str, config_lines: list[str]):
|
|
26
|
-
ob = cls()
|
|
27
29
|
config_lines_nocomments = [line.split("#", 1)[0] for line in config_lines]
|
|
28
30
|
config_lines_sep_key_and_value = [
|
|
29
31
|
# XXX removes all whitespace instead of just trim
|
|
@@ -46,8 +48,7 @@ class GDABeamlineParameters:
|
|
|
46
48
|
except Exception as e:
|
|
47
49
|
LOGGER.warning(f"Unable to parse {file_name} line {i}: {e}")
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
return ob
|
|
51
|
+
return cls(params=dict(config_pairs))
|
|
51
52
|
|
|
52
53
|
@classmethod
|
|
53
54
|
def from_file(cls, path: str):
|
|
@@ -8,14 +8,14 @@ from ophyd.sim import make_fake_device
|
|
|
8
8
|
from ophyd_async.core import Device as OphydV2Device
|
|
9
9
|
from ophyd_async.core import wait_for_connection as v2_device_wait_for_connection
|
|
10
10
|
|
|
11
|
-
from dodal.common.types import
|
|
11
|
+
from dodal.common.types import UpdatingPathProvider
|
|
12
12
|
from dodal.utils import AnyDevice, BeamlinePrefix, skip_device
|
|
13
13
|
|
|
14
14
|
DEFAULT_CONNECTION_TIMEOUT: Final[float] = 5.0
|
|
15
15
|
|
|
16
16
|
ACTIVE_DEVICES: dict[str, AnyDevice] = {}
|
|
17
17
|
BL = ""
|
|
18
|
-
|
|
18
|
+
PATH_PROVIDER: UpdatingPathProvider | None = None
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def set_beamline(beamline: str):
|
|
@@ -125,15 +125,15 @@ def device_instantiation(
|
|
|
125
125
|
return device_instance
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
def
|
|
129
|
-
global
|
|
128
|
+
def set_path_provider(provider: UpdatingPathProvider):
|
|
129
|
+
global PATH_PROVIDER
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
PATH_PROVIDER = provider
|
|
132
132
|
|
|
133
133
|
|
|
134
|
-
def
|
|
135
|
-
if
|
|
134
|
+
def get_path_provider() -> UpdatingPathProvider:
|
|
135
|
+
if PATH_PROVIDER is None:
|
|
136
136
|
raise ValueError(
|
|
137
|
-
"
|
|
137
|
+
"PathProvider has not been set! Ophyd-async StandardDetectors will not be able to write!"
|
|
138
138
|
)
|
|
139
|
-
return
|
|
139
|
+
return PATH_PROVIDER
|
dodal/common/types.py
CHANGED
|
@@ -5,7 +5,7 @@ from typing import (
|
|
|
5
5
|
)
|
|
6
6
|
|
|
7
7
|
from bluesky.utils import Msg
|
|
8
|
-
from ophyd_async.core import
|
|
8
|
+
from ophyd_async.core import PathProvider
|
|
9
9
|
|
|
10
10
|
# String identifier used by 'wait' or stubs that await
|
|
11
11
|
Group = str
|
|
@@ -15,6 +15,8 @@ MsgGenerator = Generator[Msg, Any, None]
|
|
|
15
15
|
PlanGenerator = Callable[..., MsgGenerator]
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class
|
|
18
|
+
class UpdatingPathProvider(PathProvider, ABC):
|
|
19
|
+
@abstractmethod
|
|
20
|
+
async def data_session(self) -> str: ...
|
|
19
21
|
@abstractmethod
|
|
20
22
|
async def update(self, **kwargs) -> None: ...
|
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
-
from ophyd_async.core import
|
|
3
|
+
from ophyd_async.core import FilenameProvider, PathInfo
|
|
4
4
|
|
|
5
|
-
from dodal.common.types import
|
|
5
|
+
from dodal.common.types import UpdatingPathProvider
|
|
6
6
|
from dodal.log import LOGGER
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class PandAFilenameProvider(FilenameProvider):
|
|
10
|
+
def __init__(self, suffix: str | None = None):
|
|
11
|
+
self.suffix = suffix
|
|
12
|
+
|
|
13
|
+
def __call__(self, device_name: str | None = None):
|
|
14
|
+
return f"{device_name}-{self.suffix}"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PandASubpathProvider(UpdatingPathProvider):
|
|
10
18
|
"""Directory provider for the HDFPanda. Points to a panda subdirectory within the
|
|
11
19
|
directory path provided"""
|
|
12
20
|
|
|
13
21
|
resource_dir = Path("panda")
|
|
14
22
|
|
|
15
|
-
def __init__(self,
|
|
16
|
-
|
|
23
|
+
def __init__(self, root_directory: Path | None = None, suffix: str = ""):
|
|
24
|
+
self._output_directory: Path | None = (
|
|
25
|
+
root_directory / self.resource_dir if root_directory else None
|
|
26
|
+
)
|
|
27
|
+
self._filename_provider = PandAFilenameProvider(suffix=suffix)
|
|
28
|
+
if self._output_directory is None:
|
|
17
29
|
LOGGER.debug(
|
|
18
30
|
f"{self.__class__.__name__} instantiated with no root path, update() must be called before writing data!"
|
|
19
31
|
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
else None
|
|
24
|
-
)
|
|
32
|
+
|
|
33
|
+
async def data_session(self) -> str:
|
|
34
|
+
return self._filename_provider.suffix or ""
|
|
25
35
|
|
|
26
36
|
async def update(self, *, directory: Path, suffix: str = "", **kwargs):
|
|
27
37
|
"""Update the root directory into which panda pcap files are written. This will result in the panda
|
|
@@ -32,16 +42,13 @@ class PandASubdirectoryProvider(UpdatingDirectoryProvider):
|
|
|
32
42
|
suffix: Optional str that will be appended to the panda device name along with the file
|
|
33
43
|
type extension to construct the output filename
|
|
34
44
|
"""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
self._output_directory = directory / self.resource_dir
|
|
46
|
+
self._filename_provider.suffix = suffix
|
|
47
|
+
|
|
48
|
+
def __call__(self, device_name: str | None = None) -> PathInfo:
|
|
49
|
+
assert self._output_directory, "Directory unknown for PandA to write into, update() needs to be called at least once"
|
|
50
|
+
return PathInfo(
|
|
51
|
+
directory_path=self._output_directory,
|
|
52
|
+
filename=self._filename_provider(device_name),
|
|
53
|
+
create_dir_depth=-1, # allows PandA HDFWriter to make any number of dirs
|
|
40
54
|
)
|
|
41
|
-
|
|
42
|
-
def __call__(self) -> DirectoryInfo:
|
|
43
|
-
if self._directory_info is None:
|
|
44
|
-
raise ValueError(
|
|
45
|
-
"Directory unknown for PandA to write into, update() needs to be called at least once"
|
|
46
|
-
)
|
|
47
|
-
return self._directory_info
|
dodal/common/visit.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import Literal
|
|
3
4
|
|
|
4
5
|
from aiohttp import ClientSession
|
|
5
|
-
from ophyd_async.core import
|
|
6
|
+
from ophyd_async.core import FilenameProvider, PathInfo
|
|
6
7
|
from pydantic import BaseModel
|
|
7
8
|
|
|
8
|
-
from dodal.common.types import
|
|
9
|
+
from dodal.common.types import UpdatingPathProvider
|
|
9
10
|
from dodal.log import LOGGER
|
|
10
11
|
|
|
11
12
|
"""
|
|
@@ -22,7 +23,7 @@ class DataCollectionIdentifier(BaseModel):
|
|
|
22
23
|
collectionNumber: int
|
|
23
24
|
|
|
24
25
|
|
|
25
|
-
class
|
|
26
|
+
class DirectoryServiceClient(ABC):
|
|
26
27
|
"""
|
|
27
28
|
Object responsible for I/O in determining collection number
|
|
28
29
|
"""
|
|
@@ -36,41 +37,53 @@ class DirectoryServiceClientBase(ABC):
|
|
|
36
37
|
"""Get current collection"""
|
|
37
38
|
|
|
38
39
|
|
|
39
|
-
class
|
|
40
|
+
class DiamondFilenameProvider(FilenameProvider):
|
|
41
|
+
def __init__(self, beamline: str, client: DirectoryServiceClient):
|
|
42
|
+
self._beamline = beamline
|
|
43
|
+
self._client = client
|
|
44
|
+
self.collectionId: DataCollectionIdentifier | None = None
|
|
45
|
+
|
|
46
|
+
def __call__(self, device_name: str | None = None):
|
|
47
|
+
assert device_name, "Diamond filename requires device_name to be passed"
|
|
48
|
+
assert self.collectionId is not None
|
|
49
|
+
return f"{self._beamline}-{self.collectionId.collectionNumber}-{device_name}"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class RemoteDirectoryServiceClient(DirectoryServiceClient):
|
|
40
53
|
"""Client for the VisitService REST API
|
|
41
54
|
Currently exposed by the GDA Server to co-ordinate unique filenames.
|
|
42
55
|
While VisitService is embedded in GDA, url is likely to be `ixx-control:8088/api`
|
|
43
56
|
"""
|
|
44
57
|
|
|
45
|
-
_url: str
|
|
46
|
-
|
|
47
58
|
def __init__(self, url: str) -> None:
|
|
48
59
|
self._url = url
|
|
49
60
|
|
|
50
61
|
async def create_new_collection(self) -> DataCollectionIdentifier:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
json = await response.json()
|
|
55
|
-
new_collection = DataCollectionIdentifier.parse_obj(json)
|
|
56
|
-
LOGGER.debug("New DataCollection: %s", new_collection)
|
|
57
|
-
return new_collection
|
|
62
|
+
new_collection = await self._identifier_from_response("POST")
|
|
63
|
+
LOGGER.debug("New DataCollection: %s", new_collection)
|
|
64
|
+
return new_collection
|
|
58
65
|
|
|
59
66
|
async def get_current_collection(self) -> DataCollectionIdentifier:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
json = await response.json()
|
|
64
|
-
current_collection = DataCollectionIdentifier.parse_obj(json)
|
|
65
|
-
LOGGER.debug("Current DataCollection: %s", current_collection)
|
|
66
|
-
return current_collection
|
|
67
|
-
|
|
67
|
+
current_collection = await self._identifier_from_response("GET")
|
|
68
|
+
LOGGER.debug("Current DataCollection: %s", current_collection)
|
|
69
|
+
return current_collection
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
async def _identifier_from_response(
|
|
72
|
+
self,
|
|
73
|
+
method: Literal["GET", "POST"],
|
|
74
|
+
) -> DataCollectionIdentifier:
|
|
75
|
+
async with (
|
|
76
|
+
ClientSession() as session,
|
|
77
|
+
session.request(method, f"{self._url}/numtracker") as response,
|
|
78
|
+
):
|
|
79
|
+
response.raise_for_status()
|
|
80
|
+
json = await response.json()
|
|
81
|
+
return DataCollectionIdentifier.model_validate_json(json)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class LocalDirectoryServiceClient(DirectoryServiceClient):
|
|
70
85
|
"""Local or dummy impl of VisitService client to co-ordinate unique filenames."""
|
|
71
86
|
|
|
72
|
-
_count: int
|
|
73
|
-
|
|
74
87
|
def __init__(self) -> None:
|
|
75
88
|
self._count = 0
|
|
76
89
|
|
|
@@ -84,33 +97,30 @@ class LocalDirectoryServiceClient(DirectoryServiceClientBase):
|
|
|
84
97
|
return DataCollectionIdentifier(collectionNumber=self._count)
|
|
85
98
|
|
|
86
99
|
|
|
87
|
-
class
|
|
100
|
+
class StaticVisitPathProvider(UpdatingPathProvider):
|
|
88
101
|
"""
|
|
89
|
-
Static (single visit) implementation of
|
|
102
|
+
Static (single visit) implementation of PathProvider whilst awaiting auth infrastructure to generate necessary information per-scan.
|
|
90
103
|
Allows setting a singular visit into which all run files will be saved.
|
|
91
104
|
update() queries a visit service to get the next DataCollectionIdentifier to increment the suffix of all file writers' next files.
|
|
92
105
|
Requires that all detectors are running with a mutual view on the filesystem.
|
|
93
106
|
Supports a single Visit which should be passed as a Path relative to the root of the Detector IOC mounting.
|
|
94
|
-
i.e. to write to visit /dls/ixx/data/YYYY/cm12345-1
|
|
107
|
+
i.e. to write to visit /dls/ixx/data/YYYY/cm12345-1
|
|
95
108
|
"""
|
|
96
109
|
|
|
97
|
-
_beamline: str
|
|
98
|
-
_root: Path
|
|
99
|
-
_client: DirectoryServiceClientBase
|
|
100
|
-
_current_collection: DirectoryInfo | None
|
|
101
|
-
_session: ClientSession | None
|
|
102
|
-
|
|
103
110
|
def __init__(
|
|
104
111
|
self,
|
|
105
112
|
beamline: str,
|
|
106
113
|
root: Path,
|
|
107
|
-
client:
|
|
114
|
+
client: DirectoryServiceClient | None = None,
|
|
108
115
|
):
|
|
109
116
|
self._beamline = beamline
|
|
110
|
-
self._client = client or
|
|
117
|
+
self._client = client or RemoteDirectoryServiceClient(
|
|
118
|
+
f"{beamline}-control:8088/api"
|
|
119
|
+
)
|
|
120
|
+
self._filename_provider = DiamondFilenameProvider(self._beamline, self._client)
|
|
111
121
|
self._root = root
|
|
112
|
-
self.
|
|
113
|
-
self._session
|
|
122
|
+
self.current_collection: PathInfo | None
|
|
123
|
+
self._session: ClientSession | None
|
|
114
124
|
|
|
115
125
|
async def update(self, **kwargs) -> None:
|
|
116
126
|
"""
|
|
@@ -121,33 +131,22 @@ class StaticVisitDirectoryProvider(UpdatingDirectoryProvider):
|
|
|
121
131
|
# TODO: DAQ-4827: Pass AuthN information as part of request
|
|
122
132
|
|
|
123
133
|
try:
|
|
124
|
-
|
|
125
|
-
|
|
134
|
+
self._filename_provider.collectionId = (
|
|
135
|
+
await self._client.create_new_collection()
|
|
136
|
+
)
|
|
126
137
|
except Exception:
|
|
127
138
|
LOGGER.error(
|
|
128
139
|
"Exception while updating data collection, preventing overwriting data by setting current_collection to None"
|
|
129
140
|
)
|
|
130
|
-
self.
|
|
141
|
+
self._collection_id_info = None
|
|
131
142
|
raise
|
|
132
143
|
|
|
133
|
-
def
|
|
134
|
-
self
|
|
135
|
-
|
|
136
|
-
) -> DirectoryInfo:
|
|
137
|
-
return DirectoryInfo(
|
|
138
|
-
# See DocString of DirectoryInfo. At DLS, root = visit directory, resource_dir is relative to it.
|
|
139
|
-
root=self._root,
|
|
140
|
-
# https://github.com/DiamondLightSource/dodal/issues/452
|
|
141
|
-
# Currently all h5 files written to visit/ directory, as no guarantee that visit/dataCollection/ directory will have been produced. If it is as part of #452, append the resource_dir
|
|
142
|
-
resource_dir=Path("."),
|
|
143
|
-
# Diamond standard file naming
|
|
144
|
-
prefix=f"{self._beamline}-{collection_id_info.collectionNumber}-",
|
|
145
|
-
)
|
|
144
|
+
async def data_session(self) -> str:
|
|
145
|
+
collection = await self._client.get_current_collection()
|
|
146
|
+
return f"{self._beamline}-{collection.collectionNumber}"
|
|
146
147
|
|
|
147
|
-
def __call__(self) ->
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
"No current collection, update() needs to be called at least once"
|
|
153
|
-
)
|
|
148
|
+
def __call__(self, device_name: str | None = None) -> PathInfo:
|
|
149
|
+
assert device_name, "Must call PathProvider with device_name"
|
|
150
|
+
return PathInfo(
|
|
151
|
+
directory_path=self._root, filename=self._filename_provider(device_name)
|
|
152
|
+
)
|
dodal/devices/CTAB.py
CHANGED
dodal/devices/aperture.py
CHANGED