mx-bluesky 1.4.8__py3-none-any.whl → 1.4.9__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 (49) hide show
  1. mx_bluesky/_version.py +2 -2
  2. mx_bluesky/beamlines/aithre_lasershaping/__init__.py +8 -0
  3. mx_bluesky/beamlines/aithre_lasershaping/beamline_safe.py +36 -0
  4. mx_bluesky/beamlines/aithre_lasershaping/goniometer_controls.py +43 -0
  5. mx_bluesky/beamlines/i24/serial/blueapi_config.yaml +2 -1
  6. mx_bluesky/beamlines/i24/serial/dcid.py +5 -5
  7. mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DetStage.edl +2 -2
  8. mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +9 -9
  9. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +18 -3
  10. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DetStage.edl +2 -2
  11. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +14 -14
  12. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +2 -2
  13. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +23 -4
  14. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +7 -1
  15. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +0 -8
  16. mx_bluesky/common/device_setup_plans/manipulate_sample.py +5 -13
  17. mx_bluesky/common/external_interaction/nexus/nexus_utils.py +2 -2
  18. mx_bluesky/common/utils/log.py +12 -11
  19. mx_bluesky/hyperion/__main__.py +6 -11
  20. mx_bluesky/hyperion/baton_handler.py +8 -3
  21. mx_bluesky/hyperion/device_setup_plans/smargon.py +2 -7
  22. mx_bluesky/hyperion/device_setup_plans/utils.py +4 -3
  23. mx_bluesky/hyperion/experiment_plans/__init__.py +2 -2
  24. mx_bluesky/hyperion/experiment_plans/experiment_registry.py +3 -4
  25. mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +10 -0
  26. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +40 -10
  27. mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +3 -0
  28. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +2 -11
  29. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +22 -25
  30. mx_bluesky/hyperion/external_interaction/agamemnon.py +68 -62
  31. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +1 -1
  32. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +3 -3
  33. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +6 -3
  34. mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +2 -2
  35. mx_bluesky/hyperion/external_interaction/config_server.py +4 -1
  36. mx_bluesky/hyperion/parameters/cli.py +3 -10
  37. mx_bluesky/hyperion/parameters/constants.py +1 -0
  38. mx_bluesky/hyperion/parameters/load_centre_collect.py +4 -4
  39. mx_bluesky/hyperion/parameters/rotation.py +9 -8
  40. mx_bluesky/hyperion/utils/context.py +5 -2
  41. mx_bluesky/hyperion/utils/validation.py +10 -17
  42. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/METADATA +4 -4
  43. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/RECORD +47 -48
  44. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/WHEEL +1 -1
  45. mx_bluesky/common/device_setup_plans/check_beamstop.py +0 -27
  46. mx_bluesky/common/external_interaction/test_config_server.py +0 -38
  47. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/entry_points.txt +0 -0
  48. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/licenses/LICENSE +0 -0
  49. {mx_bluesky-1.4.8.dist-info → mx_bluesky-1.4.9.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,7 @@ import dataclasses
2
2
  import json
3
3
  import re
4
4
  import traceback
5
+ from collections.abc import Sequence
5
6
  from os import path
6
7
  from typing import Any, TypeVar
7
8
 
@@ -127,83 +128,88 @@ def get_param_version() -> SemanticVersion:
127
128
  return SemanticVersion.validate_from_str(str(PARAMETER_VERSION))
128
129
 
129
130
 
130
- def populate_parameters_from_agamemnon(agamemnon_params):
131
+ def populate_parameters_from_agamemnon(agamemnon_params) -> Sequence[LoadCentreCollect]:
131
132
  visit, detector_distance = get_withvisit_parameters_from_agamemnon(agamemnon_params)
132
133
  with_energy_params = get_withenergy_parameters_from_agamemnon(agamemnon_params)
133
134
  pin_type = get_pin_type_from_agamemnon_parameters(agamemnon_params)
134
- first_collection = agamemnon_params["collection"][0]
135
+ collections = agamemnon_params["collection"]
135
136
  visit_directory, file_name = path.split(agamemnon_params["prefix"])
136
- return LoadCentreCollect.model_validate(
137
- {
138
- "parameter_model_version": get_param_version(),
139
- "visit": visit,
140
- "detector_distance_mm": detector_distance,
141
- "sample_id": agamemnon_params["sample"]["id"],
142
- "sample_puck": agamemnon_params["sample"]["container"],
143
- "sample_pin": agamemnon_params["sample"]["position"],
144
- "select_centres": {
145
- "name": "TopNByMaxCount",
146
- "n": pin_type.expected_number_of_crystals,
147
- },
148
- "robot_load_then_centre": {
149
- "storage_directory": str(visit_directory) + "/xraycentring",
150
- "file_name": file_name,
151
- "tip_offset_um": pin_type.full_width / 2,
152
- "grid_width_um": pin_type.full_width,
153
- "omega_start_deg": 0.0,
154
- "chi_start_deg": first_collection["chi"],
155
- "transmission_frac": 1.0,
156
- "features": {"use_gpu_results": True},
157
- **with_energy_params,
158
- },
159
- "multi_rotation_scan": {
160
- "comment": first_collection["comment"],
161
- "storage_directory": str(visit_directory),
162
- "exposure_time_s": first_collection["exposure_time"],
163
- "file_name": file_name,
164
- "transmission_frac": first_collection["transmission"],
165
- "rotation_increment_deg": first_collection["omega_increment"],
166
- "ispyb_experiment_type": first_collection["experiment_type"],
167
- "snapshot_omegas_deg": [0.0, 90.0, 180.0, 270.0],
168
- "rotation_scans": [
169
- {
170
- "scan_width_deg": (
171
- first_collection["number_of_images"]
172
- * first_collection["omega_increment"]
173
- ),
174
- "omega_start_deg": first_collection["omega_start"],
175
- "phi_start_deg": first_collection["phi_start"],
176
- "chi_start_deg": first_collection["chi"],
177
- "rotation_direction": "Positive",
178
- }
179
- ],
180
- **with_energy_params,
181
- },
182
- }
183
- )
137
+
138
+ return [
139
+ LoadCentreCollect.model_validate(
140
+ {
141
+ "parameter_model_version": get_param_version(),
142
+ "visit": visit,
143
+ "detector_distance_mm": detector_distance,
144
+ "sample_id": agamemnon_params["sample"]["id"],
145
+ "sample_puck": agamemnon_params["sample"]["container"],
146
+ "sample_pin": agamemnon_params["sample"]["position"],
147
+ "select_centres": {
148
+ "name": "TopNByMaxCount",
149
+ "n": pin_type.expected_number_of_crystals,
150
+ },
151
+ "robot_load_then_centre": {
152
+ "storage_directory": str(visit_directory) + "/xraycentring",
153
+ "file_name": file_name,
154
+ "tip_offset_um": pin_type.full_width / 2,
155
+ "grid_width_um": pin_type.full_width,
156
+ "omega_start_deg": 0.0,
157
+ "chi_start_deg": collection["chi"],
158
+ "transmission_frac": 1.0,
159
+ "features": {"use_gpu_results": True},
160
+ **with_energy_params,
161
+ },
162
+ "multi_rotation_scan": {
163
+ "comment": collection["comment"],
164
+ "storage_directory": str(visit_directory),
165
+ "exposure_time_s": collection["exposure_time"],
166
+ "file_name": file_name,
167
+ "transmission_frac": collection["transmission"],
168
+ "rotation_increment_deg": collection["omega_increment"],
169
+ "ispyb_experiment_type": collection["experiment_type"],
170
+ "snapshot_omegas_deg": [0.0, 90.0, 180.0, 270.0],
171
+ "rotation_scans": [
172
+ {
173
+ "scan_width_deg": (
174
+ collection["number_of_images"]
175
+ * collection["omega_increment"]
176
+ ),
177
+ "omega_start_deg": collection["omega_start"],
178
+ "phi_start_deg": collection["phi_start"],
179
+ "chi_start_deg": collection["chi"],
180
+ "rotation_direction": "Positive",
181
+ }
182
+ ],
183
+ **with_energy_params,
184
+ },
185
+ }
186
+ )
187
+ for collection in collections
188
+ ]
184
189
 
185
190
 
186
- def create_parameters_from_agamemnon() -> LoadCentreCollect | None:
191
+ def create_parameters_from_agamemnon() -> Sequence[LoadCentreCollect]:
187
192
  beamline_name = get_beamline_name("i03")
188
193
  agamemnon_params = get_next_instruction(beamline_name)
189
194
  return (
190
- populate_parameters_from_agamemnon(agamemnon_params)
191
- if agamemnon_params
192
- else None
195
+ populate_parameters_from_agamemnon(agamemnon_params) if agamemnon_params else []
193
196
  )
194
197
 
195
198
 
196
- def compare_params(load_centre_collect_params):
199
+ def compare_params(load_centre_collect_params: LoadCentreCollect):
197
200
  try:
198
- parameters = create_parameters_from_agamemnon()
201
+ lcc_requests = create_parameters_from_agamemnon()
199
202
  # Log differences against GDA populated parameters
200
- differences = DeepDiff(
201
- parameters, load_centre_collect_params, math_epsilon=1e-5
202
- )
203
- if differences:
204
- LOGGER.info(
205
- f"Different parameters found when directly reading from Hyperion: {differences}"
203
+ if not lcc_requests:
204
+ LOGGER.info("Agamemnon returned no instructions")
205
+ else:
206
+ differences = DeepDiff(
207
+ lcc_requests[0], load_centre_collect_params, math_epsilon=1e-5
206
208
  )
209
+ if differences:
210
+ LOGGER.info(
211
+ f"Different parameters found when directly reading from Hyperion: {differences}"
212
+ )
207
213
  except (ValueError, KeyError):
208
214
  LOGGER.warning(f"Failed to compare parameters: {traceback.format_exc()}")
209
215
  except Exception:
@@ -93,7 +93,7 @@ def setup_logging(dev_mode: bool):
93
93
  (ISPYB_ZOCALO_CALLBACK_LOGGER, "hyperion_ispyb_callback.log"),
94
94
  (NEXUS_LOGGER, "hyperion_nexus_callback.log"),
95
95
  ]:
96
- logging_path, debug_logging_path = _get_logging_dirs()
96
+ logging_path, debug_logging_path = _get_logging_dirs(dev_mode)
97
97
  if logger.handlers == []:
98
98
  handlers = set_up_all_logging_handlers(
99
99
  logger,
@@ -25,7 +25,7 @@ from mx_bluesky.hyperion.external_interaction.callbacks.rotation.ispyb_mapping i
25
25
  populate_data_collection_info_for_rotation,
26
26
  )
27
27
  from mx_bluesky.hyperion.parameters.constants import CONST
28
- from mx_bluesky.hyperion.parameters.rotation import RotationScan
28
+ from mx_bluesky.hyperion.parameters.rotation import SingleRotationScan
29
29
 
30
30
  if TYPE_CHECKING:
31
31
  from event_model.documents import Event, RunStart, RunStop
@@ -62,7 +62,7 @@ class RotationISPyBCallback(BaseISPyBCallback):
62
62
  )
63
63
  hyperion_params = doc.get("mx_bluesky_parameters")
64
64
  assert isinstance(hyperion_params, str)
65
- self.params = RotationScan.model_validate_json(hyperion_params)
65
+ self.params = SingleRotationScan.model_validate_json(hyperion_params)
66
66
  dcgid = (
67
67
  self.ispyb_ids.data_collection_group_id
68
68
  if (self.params.sample_id == self.last_sample_id)
@@ -86,7 +86,7 @@ class RotationISPyBCallback(BaseISPyBCallback):
86
86
  ISPYB_ZOCALO_CALLBACK_LOGGER.info("Beginning ispyb deposition")
87
87
  data_collection_group_info = populate_data_collection_group(self.params)
88
88
  data_collection_info = populate_data_collection_info_for_rotation(
89
- cast(RotationScan, self.params)
89
+ cast(SingleRotationScan, self.params)
90
90
  )
91
91
  data_collection_info = populate_remaining_data_collection_info(
92
92
  self.params.comment,
@@ -1,17 +1,20 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from mx_bluesky.common.external_interaction.ispyb.data_model import DataCollectionInfo
4
- from mx_bluesky.hyperion.parameters.rotation import RotationScan
4
+ from mx_bluesky.hyperion.parameters.rotation import SingleRotationScan
5
5
 
6
6
 
7
- def populate_data_collection_info_for_rotation(params: RotationScan):
7
+ def populate_data_collection_info_for_rotation(params: SingleRotationScan):
8
8
  info = DataCollectionInfo(
9
9
  omega_start=params.omega_start_deg,
10
10
  data_collection_number=params.detector_params.run_number, # type:ignore # the validator always makes this int
11
11
  n_images=params.num_images,
12
12
  axis_range=params.rotation_increment_deg,
13
13
  axis_start=params.omega_start_deg,
14
- axis_end=(params.omega_start_deg + params.scan_width_deg),
14
+ axis_end=(
15
+ params.omega_start_deg
16
+ + params.scan_width_deg * params.rotation_direction.multiplier
17
+ ),
15
18
  kappa_start=params.kappa_start_deg,
16
19
  )
17
20
  return info
@@ -16,7 +16,7 @@ from mx_bluesky.common.external_interaction.nexus.nexus_utils import (
16
16
  from mx_bluesky.common.external_interaction.nexus.write_nexus import NexusWriter
17
17
  from mx_bluesky.common.utils.log import NEXUS_LOGGER
18
18
  from mx_bluesky.hyperion.parameters.constants import CONST
19
- from mx_bluesky.hyperion.parameters.rotation import RotationScan
19
+ from mx_bluesky.hyperion.parameters.rotation import SingleRotationScan
20
20
 
21
21
  if TYPE_CHECKING:
22
22
  from event_model.documents import Event, EventDescriptor, RunStart
@@ -85,7 +85,7 @@ class RotationNexusFileCallback(PlanReactiveCallback):
85
85
  NEXUS_LOGGER.info(
86
86
  f"Nexus writer received start document with experiment parameters {hyperion_params}"
87
87
  )
88
- parameters = RotationScan.model_validate_json(hyperion_params)
88
+ parameters = SingleRotationScan.model_validate_json(hyperion_params)
89
89
  NEXUS_LOGGER.info("Setting up nexus file...")
90
90
 
91
91
  det_size = (
@@ -21,7 +21,9 @@ class HyperionFeatureFlags(FeatureFlags):
21
21
  set_stub_offsets: If True then set the stub offsets after moving to the crystal (ignored for
22
22
  multi-centre)
23
23
  omega_flip: If True then invert the smargon omega motor rotation commands with respect to
24
- the hyperion request.
24
+ the hyperion request. See "Hyperion Coordinate Systems" in the documentation.
25
+ alternate_rotation_direction: If True then the for multi-sample pins the rotation direction of
26
+ successive rotation scans is alternated between positive and negative.
25
27
  """
26
28
 
27
29
  @staticmethod
@@ -41,3 +43,4 @@ class HyperionFeatureFlags(FeatureFlags):
41
43
  use_gpu_results: bool = CONST.I03.USE_GPU_RESULTS
42
44
  set_stub_offsets: bool = CONST.I03.SET_STUB_OFFSETS
43
45
  omega_flip: bool = CONST.I03.OMEGA_FLIP
46
+ alternate_rotation_direction: bool = CONST.I03.ALTERNATE_ROTATION_DIRECTION
@@ -8,7 +8,6 @@ from mx_bluesky._version import version
8
8
  @dataclass
9
9
  class HyperionArgs:
10
10
  dev_mode: bool = False
11
- verbose_event_logging: bool = False
12
11
 
13
12
 
14
13
  def _add_callback_relevant_args(parser: argparse.ArgumentParser) -> None:
@@ -29,16 +28,11 @@ def parse_callback_dev_mode_arg() -> bool:
29
28
 
30
29
 
31
30
  def parse_cli_args() -> HyperionArgs:
32
- """Parses all arguments relevant to hyperion. Returns an HyperionArgs dataclass with
33
- the fields: (verbose_event_logging: bool,
34
- dev_mode: bool)"""
31
+ """Parses all arguments relevant to hyperion.
32
+ Returns:
33
+ an HyperionArgs dataclass with the fields: (dev_mode: bool)"""
35
34
  parser = argparse.ArgumentParser()
36
35
  _add_callback_relevant_args(parser)
37
- parser.add_argument(
38
- "--verbose-event-logging",
39
- action="store_true",
40
- help="Log all bluesky event documents to graylog",
41
- )
42
36
  parser.add_argument(
43
37
  "--version",
44
38
  help="Print hyperion version string",
@@ -47,6 +41,5 @@ def parse_cli_args() -> HyperionArgs:
47
41
  )
48
42
  args = parser.parse_args()
49
43
  return HyperionArgs(
50
- verbose_event_logging=args.verbose_event_logging or False,
51
44
  dev_mode=args.dev or False,
52
45
  )
@@ -28,6 +28,7 @@ class I03Constants:
28
28
  USE_PANDA_FOR_GRIDSCAN = False
29
29
  SET_STUB_OFFSETS = False
30
30
  OMEGA_FLIP = True
31
+ ALTERNATE_ROTATION_DIRECTION = True
31
32
 
32
33
  # Turns on GPU processing for zocalo and logs a comparison between GPU and CPU-
33
34
  # processed results.
@@ -12,7 +12,7 @@ from mx_bluesky.hyperion.parameters.components import WithHyperionUDCFeatures
12
12
  from mx_bluesky.hyperion.parameters.robot_load import (
13
13
  RobotLoadThenCentre,
14
14
  )
15
- from mx_bluesky.hyperion.parameters.rotation import MultiRotationScan
15
+ from mx_bluesky.hyperion.parameters.rotation import RotationScan
16
16
 
17
17
  T = TypeVar("T", bound=BaseModel)
18
18
 
@@ -34,7 +34,7 @@ class LoadCentreCollect(
34
34
  pin-tip centre and rotation scan operations."""
35
35
 
36
36
  robot_load_then_centre: RobotLoadThenCentre
37
- multi_rotation_scan: MultiRotationScan
37
+ multi_rotation_scan: RotationScan
38
38
 
39
39
  @model_validator(mode="before")
40
40
  @classmethod
@@ -42,7 +42,7 @@ class LoadCentreCollect(
42
42
  allowed_keys = (
43
43
  LoadCentreCollect.model_fields.keys()
44
44
  | RobotLoadThenCentre.model_fields.keys()
45
- | MultiRotationScan.model_fields.keys()
45
+ | RotationScan.model_fields.keys()
46
46
  )
47
47
 
48
48
  disallowed_keys = values.keys() - allowed_keys
@@ -74,7 +74,7 @@ class LoadCentreCollect(
74
74
  values, values["robot_load_then_centre"], RobotLoadThenCentre
75
75
  )
76
76
  new_multi_rotation_scan_params = construct_from_values(
77
- values, values["multi_rotation_scan"], MultiRotationScan
77
+ values, values["multi_rotation_scan"], RotationScan
78
78
  )
79
79
  values["multi_rotation_scan"] = new_multi_rotation_scan_params
80
80
  values["robot_load_then_centre"] = new_robot_load_then_centre_params
@@ -42,7 +42,8 @@ class RotationScanPerSweep(OptionalGonioAngleStarts, OptionalXyzStarts):
42
42
  omega_start_deg: The initial angle of the rotation in degrees (default 0)
43
43
  scan_width_deg: The sweep of the rotation in degrees, this must be positive (default 360)
44
44
  rotation_direction: Indicates the direction of rotation, if RotationDirection.POSITIVE
45
- the final angle is obtained by adding scan_width_deg, otherwise by subtraction (default NEGATIVE)
45
+ the final angle is obtained by adding scan_width_deg, otherwise by subtraction (default NEGATIVE).
46
+ See "Hyperion Coordinate Systems" in the documentation.
46
47
  nexus_vds_start_img: The frame number of the first frame captured during the rotation
47
48
  """
48
49
 
@@ -104,7 +105,7 @@ class RotationExperiment(DiffractionExperimentWithSample, WithHyperionUDCFeature
104
105
  return aperture_position
105
106
 
106
107
 
107
- class RotationScan(WithScan, RotationScanPerSweep, RotationExperiment):
108
+ class SingleRotationScan(WithScan, RotationScanPerSweep, RotationExperiment):
108
109
  @property
109
110
  def detector_params(self):
110
111
  return self._detector_params(self.omega_start_deg)
@@ -129,12 +130,12 @@ class RotationScan(WithScan, RotationScanPerSweep, RotationExperiment):
129
130
  return int(self.scan_width_deg / self.rotation_increment_deg)
130
131
 
131
132
 
132
- class MultiRotationScan(RotationExperiment, SplitScan):
133
+ class RotationScan(RotationExperiment, SplitScan):
133
134
  rotation_scans: Annotated[list[RotationScanPerSweep], Len(min_length=1)]
134
135
 
135
- def _single_rotation_scan(self, scan: RotationScanPerSweep) -> RotationScan:
136
+ def _single_rotation_scan(self, scan: RotationScanPerSweep) -> SingleRotationScan:
136
137
  # self has everything from RotationExperiment
137
- allowed_keys = RotationScan.model_fields.keys() # type: ignore # mypy doesn't recognise this as a property...
138
+ allowed_keys = SingleRotationScan.model_fields.keys() # type: ignore # mypy doesn't recognise this as a property...
138
139
  params_dump = self.model_dump()
139
140
  # provided `scan` has everything from RotationScanPerSweep
140
141
  scan_dump = scan.model_dump()
@@ -142,13 +143,13 @@ class MultiRotationScan(RotationExperiment, SplitScan):
142
143
  k: v for k, v in (params_dump | scan_dump).items() if k in allowed_keys
143
144
  }
144
145
  # together they have everything for RotationScan
145
- rotation_scan = RotationScan(**rotation_scan_kv_pairs)
146
+ rotation_scan = SingleRotationScan(**rotation_scan_kv_pairs)
146
147
  return rotation_scan
147
148
 
148
149
  @model_validator(mode="after")
149
150
  @classmethod
150
151
  def correct_start_vds(cls, values: Any) -> Any:
151
- assert isinstance(values, MultiRotationScan)
152
+ assert isinstance(values, RotationScan)
152
153
  start_img = 0.0
153
154
  for scan in values.rotation_scans:
154
155
  scan.nexus_vds_start_img = int(start_img)
@@ -167,7 +168,7 @@ class MultiRotationScan(RotationExperiment, SplitScan):
167
168
  return self
168
169
 
169
170
  @property
170
- def single_rotation_scans(self) -> Iterator[RotationScan]:
171
+ def single_rotation_scans(self) -> Iterator[SingleRotationScan]:
171
172
  for scan in self.rotation_scans:
172
173
  yield self._single_rotation_scan(scan)
173
174
 
@@ -5,11 +5,14 @@ import mx_bluesky.hyperion.experiment_plans as hyperion_plans
5
5
  from mx_bluesky.common.utils.log import LOGGER
6
6
 
7
7
 
8
- def setup_context() -> BlueskyContext:
8
+ def setup_context(dev_mode: bool = False) -> BlueskyContext:
9
9
  context = BlueskyContext()
10
10
  context.with_plan_module(hyperion_plans)
11
11
 
12
- context.with_dodal_module(get_beamline_based_on_environment_variable())
12
+ context.with_dodal_module(
13
+ get_beamline_based_on_environment_variable(),
14
+ mock=dev_mode,
15
+ )
13
16
 
14
17
  LOGGER.info(f"Plans found in context: {context.plan_functions.keys()}")
15
18
 
@@ -3,12 +3,11 @@ import json
3
3
  import os
4
4
  import shutil
5
5
  from pathlib import Path
6
- from unittest.mock import patch
7
6
 
8
7
  import bluesky.preprocessors as bpp
9
8
  from bluesky.run_engine import RunEngine
10
9
  from dodal.beamlines import i03
11
- from dodal.devices.oav.oav_parameters import OAVConfig
10
+ from dodal.devices.oav.oav_detector import OAVConfigBeamCentre
12
11
  from ophyd_async.testing import set_mock_value
13
12
 
14
13
  from mx_bluesky.common.plans.read_hardware import (
@@ -21,7 +20,7 @@ from mx_bluesky.hyperion.external_interaction.callbacks.rotation.nexus_callback
21
20
  RotationNexusFileCallback,
22
21
  )
23
22
  from mx_bluesky.hyperion.parameters.constants import CONST
24
- from mx_bluesky.hyperion.parameters.rotation import MultiRotationScan
23
+ from mx_bluesky.hyperion.parameters.rotation import RotationScan
25
24
 
26
25
  DISPLAY_CONFIGURATION = "tests/test_data/test_display.configuration"
27
26
  ZOOM_LEVELS_XML = "tests/test_data/test_jCameraManZoomLevels.xml"
@@ -36,7 +35,7 @@ def test_params(filename_stub, dir):
36
35
  with open(filename) as f:
37
36
  return json.loads(f.read())
38
37
 
39
- params = MultiRotationScan(
38
+ params = RotationScan(
40
39
  **get_params(
41
40
  "tests/test_data/parameter_json_files/good_test_one_multi_rotation_scan_parameters.json"
42
41
  )
@@ -54,7 +53,7 @@ def test_params(filename_stub, dir):
54
53
 
55
54
 
56
55
  def fake_rotation_scan(
57
- parameters: MultiRotationScan,
56
+ parameters: RotationScan,
58
57
  subscription: RotationNexusFileCallback,
59
58
  rotation_devices: RotationScanComposite,
60
59
  ):
@@ -101,9 +100,7 @@ def fake_create_rotation_devices():
101
100
  oav = i03.oav(
102
101
  connect_immediately=True,
103
102
  mock=True,
104
- params=OAVConfig(
105
- zoom_params_file=ZOOM_LEVELS_XML, display_config_file=DISPLAY_CONFIGURATION
106
- ),
103
+ params=OAVConfigBeamCentre(ZOOM_LEVELS_XML, DISPLAY_CONFIGURATION),
107
104
  )
108
105
  xbpm_feedback = i03.xbpm_feedback(connect_immediately=True, mock=True)
109
106
 
@@ -132,7 +129,7 @@ def fake_create_rotation_devices():
132
129
 
133
130
 
134
131
  def sim_rotation_scan_to_create_nexus(
135
- test_params: MultiRotationScan,
132
+ test_params: RotationScan,
136
133
  fake_create_rotation_devices: RotationScanComposite,
137
134
  filename_stub,
138
135
  RE,
@@ -142,15 +139,11 @@ def sim_rotation_scan_to_create_nexus(
142
139
 
143
140
  fake_create_rotation_devices.eiger.bit_depth.sim_put(32) # type: ignore
144
141
 
145
- with patch(
146
- "mx_bluesky.common.external_interaction.nexus.write_nexus.get_start_and_predicted_end_time",
147
- return_value=("test_time", "test_time"),
148
- ):
149
- RE(
150
- fake_rotation_scan(
151
- test_params, RotationNexusFileCallback(), fake_create_rotation_devices
152
- )
142
+ RE(
143
+ fake_rotation_scan(
144
+ test_params, RotationNexusFileCallback(), fake_create_rotation_devices
153
145
  )
146
+ )
154
147
 
155
148
  nexus_path = Path(test_params.storage_directory) / nexus_filename
156
149
  assert os.path.isfile(nexus_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mx-bluesky
3
- Version: 1.4.8
3
+ Version: 1.4.9
4
4
  Summary: Bluesky tools for MX Beamlines at DLS
5
5
  Author-email: Dominic Oram <dominic.oram@diamond.ac.uk>
6
6
  License: Apache License
@@ -220,7 +220,7 @@ Requires-Dist: flask-restful
220
220
  Requires-Dist: ispyb
221
221
  Requires-Dist: jupyterlab
222
222
  Requires-Dist: matplotlib
223
- Requires-Dist: nexgen
223
+ Requires-Dist: nexgen>=0.11.0
224
224
  Requires-Dist: numpy
225
225
  Requires-Dist: opencv-python
226
226
  Requires-Dist: opentelemetry-distro
@@ -235,11 +235,11 @@ Requires-Dist: scipy
235
235
  Requires-Dist: semver
236
236
  Requires-Dist: matplotlib
237
237
  Requires-Dist: blueapi>=0.5.0
238
- Requires-Dist: daq-config-server>=0.1.1
238
+ Requires-Dist: daq-config-server==0.1.1
239
239
  Requires-Dist: ophyd>=1.10.5
240
240
  Requires-Dist: ophyd-async>=0.10.0a2
241
241
  Requires-Dist: bluesky>=1.13.1
242
- Requires-Dist: dls-dodal==1.47.0
242
+ Requires-Dist: dls-dodal==1.48.0
243
243
  Provides-Extra: dev
244
244
  Requires-Dist: black; extra == "dev"
245
245
  Requires-Dist: build; extra == "dev"