dls-dodal 1.68.0__py3-none-any.whl → 2.0.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 (292) hide show
  1. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/METADATA +1 -31
  2. dls_dodal-2.0.0.dist-info/RECORD +354 -0
  3. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/WHEEL +1 -1
  4. dodal/_version.py +2 -2
  5. dodal/beamlines/__init__.py +10 -17
  6. dodal/beamlines/adsim.py +40 -33
  7. dodal/beamlines/b01_1.py +11 -0
  8. dodal/beamlines/b07.py +17 -21
  9. dodal/beamlines/b07_1.py +20 -22
  10. dodal/beamlines/b07_shared.py +12 -0
  11. dodal/beamlines/b16.py +1 -1
  12. dodal/beamlines/b21.py +15 -6
  13. dodal/beamlines/i02_1.py +17 -45
  14. dodal/beamlines/i02_2.py +6 -12
  15. dodal/beamlines/i03.py +8 -5
  16. dodal/beamlines/i03_supervisor.py +19 -0
  17. dodal/beamlines/i04.py +87 -184
  18. dodal/beamlines/i05.py +9 -39
  19. dodal/beamlines/i05_1.py +4 -13
  20. dodal/beamlines/i05_shared.py +51 -0
  21. dodal/beamlines/i06_1.py +26 -0
  22. dodal/beamlines/{i06.py → i06_shared.py} +25 -14
  23. dodal/beamlines/i07.py +14 -16
  24. dodal/beamlines/i09.py +76 -29
  25. dodal/beamlines/i09_1.py +25 -56
  26. dodal/beamlines/i09_1_shared.py +61 -0
  27. dodal/beamlines/i09_2.py +6 -100
  28. dodal/beamlines/i09_2_shared.py +110 -0
  29. dodal/beamlines/i10.py +60 -54
  30. dodal/beamlines/i10_1.py +99 -10
  31. dodal/beamlines/{i10_optics.py → i10_shared.py} +80 -66
  32. dodal/beamlines/i11.py +31 -18
  33. dodal/beamlines/i13_1.py +1 -1
  34. dodal/beamlines/i15.py +6 -6
  35. dodal/beamlines/i15_1.py +6 -6
  36. dodal/beamlines/i16.py +11 -0
  37. dodal/beamlines/i17.py +37 -28
  38. dodal/beamlines/i18.py +3 -4
  39. dodal/beamlines/i19_1.py +95 -34
  40. dodal/beamlines/i19_2.py +68 -52
  41. dodal/beamlines/i19_optics.py +26 -13
  42. dodal/beamlines/i20_1.py +17 -11
  43. dodal/beamlines/i21.py +44 -29
  44. dodal/beamlines/i22.py +19 -4
  45. dodal/beamlines/i23.py +20 -27
  46. dodal/beamlines/i24.py +64 -113
  47. dodal/beamlines/k07.py +99 -5
  48. dodal/beamlines/p38.py +3 -3
  49. dodal/beamlines/p60.py +35 -14
  50. dodal/beamlines/p99.py +16 -15
  51. dodal/beamlines/training_rig.py +20 -12
  52. dodal/cli.py +36 -2
  53. dodal/common/__init__.py +2 -1
  54. dodal/common/beamlines/beamline_parameters.py +2 -1
  55. dodal/common/beamlines/beamline_utils.py +11 -9
  56. dodal/common/beamlines/commissioning_mode.py +6 -3
  57. dodal/common/coordination.py +12 -14
  58. dodal/common/crystal_metadata.py +5 -8
  59. dodal/common/device_utils.py +4 -3
  60. dodal/common/maths.py +87 -19
  61. dodal/common/udc_directory_provider.py +13 -8
  62. dodal/common/visit.py +18 -21
  63. dodal/common/watcher_utils.py +13 -12
  64. dodal/device_manager.py +94 -54
  65. dodal/devices/aperturescatterguard.py +26 -27
  66. dodal/devices/areadetector/plugins/cam.py +1 -3
  67. dodal/devices/areadetector/plugins/mjpg.py +6 -5
  68. dodal/devices/attenuator/attenuator.py +12 -11
  69. dodal/devices/beamlines/b07/__init__.py +3 -0
  70. dodal/devices/{b07_1 → beamlines/b07_1}/__init__.py +2 -2
  71. dodal/devices/{b07_1 → beamlines/b07_1}/ccmc.py +5 -10
  72. dodal/devices/{b16 → beamlines/b16}/detector.py +2 -3
  73. dodal/devices/{i02_1 → beamlines/i02_1}/fast_grid_scan.py +2 -3
  74. dodal/devices/{i02_1 → beamlines/i02_1}/sample_motors.py +1 -1
  75. dodal/devices/{i03 → beamlines/i03}/beamsize.py +11 -7
  76. dodal/devices/{i03 → beamlines/i03}/dcm.py +1 -2
  77. dodal/devices/{i03 → beamlines/i03}/undulator_dcm.py +4 -5
  78. dodal/devices/beamlines/i04/beam_centre.py +151 -0
  79. dodal/devices/{i04 → beamlines/i04}/beamsize.py +11 -7
  80. dodal/devices/beamlines/i04/max_pixel.py +25 -0
  81. dodal/devices/{i04 → beamlines/i04}/murko_results.py +23 -8
  82. dodal/devices/{i04 → beamlines/i04}/transfocator.py +10 -15
  83. dodal/devices/beamlines/i05/__init__.py +3 -0
  84. dodal/devices/beamlines/i06_shared/__init__.py +3 -0
  85. dodal/devices/beamlines/i06_shared/i06_enum.py +7 -0
  86. dodal/devices/{i07 → beamlines/i07}/dcm.py +2 -3
  87. dodal/devices/{i07 → beamlines/i07}/id.py +8 -9
  88. dodal/devices/beamlines/i09/__init__.py +3 -0
  89. dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_energy.py +5 -6
  90. dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_undulator_functions.py +19 -16
  91. dodal/devices/{i10 → beamlines/i10}/diagnostics.py +4 -3
  92. dodal/devices/{i10 → beamlines/i10}/i10_apple2.py +37 -51
  93. dodal/devices/{i10 → beamlines/i10}/rasor/rasor_current_amp.py +1 -24
  94. dodal/devices/{i10 → beamlines/i10}/rasor/rasor_motors.py +2 -2
  95. dodal/devices/{i10 → beamlines/i10}/slits.py +5 -3
  96. dodal/devices/beamlines/i10_1/__init__.py +9 -0
  97. dodal/devices/beamlines/i10_1/electromagnet/magnet.py +16 -0
  98. dodal/devices/beamlines/i10_1/electromagnet/stages.py +14 -0
  99. dodal/devices/beamlines/i10_1/scaler_cards.py +13 -0
  100. dodal/devices/{i11 → beamlines/i11}/cyberstar_blower.py +1 -1
  101. dodal/devices/{i11 → beamlines/i11}/diff_stages.py +4 -6
  102. dodal/devices/{i11 → beamlines/i11}/mythen.py +3 -4
  103. dodal/devices/{i11 → beamlines/i11}/nx100robot.py +6 -6
  104. dodal/devices/{i11 → beamlines/i11}/spinner.py +1 -1
  105. dodal/devices/{i13_1 → beamlines/i13_1}/merlin.py +1 -1
  106. dodal/devices/{i15 → beamlines/i15}/dcm.py +1 -2
  107. dodal/devices/{i15 → beamlines/i15}/focussing_mirror.py +5 -5
  108. dodal/devices/{i15 → beamlines/i15}/jack.py +2 -2
  109. dodal/devices/{i15 → beamlines/i15}/multilayer_mirror.py +1 -1
  110. dodal/devices/{i17 → beamlines/i17}/i17_apple2.py +16 -22
  111. dodal/devices/{i18 → beamlines/i18}/diode.py +1 -1
  112. dodal/devices/{i19 → beamlines/i19}/access_controlled/attenuator_motor_squad.py +12 -8
  113. dodal/devices/{i19 → beamlines/i19}/access_controlled/blueapi_device.py +16 -15
  114. dodal/devices/beamlines/i19/access_controlled/piezo_control.py +72 -0
  115. dodal/devices/{i19 → beamlines/i19}/access_controlled/shutter.py +11 -9
  116. dodal/devices/{i19 → beamlines/i19}/backlight.py +3 -1
  117. dodal/devices/{i19 → beamlines/i19}/mapt_configuration.py +2 -1
  118. dodal/devices/{i19 → beamlines/i19}/pin_col_stages.py +11 -8
  119. dodal/devices/beamlines/i19/pin_tip.py +32 -0
  120. dodal/devices/beamlines/i21/__init__.py +3 -0
  121. dodal/devices/{i22 → beamlines/i22}/dcm.py +1 -2
  122. dodal/devices/{i22 → beamlines/i22}/fswitch.py +1 -3
  123. dodal/devices/{i22 → beamlines/i22}/nxsas.py +5 -4
  124. dodal/devices/{i24 → beamlines/i24}/beam_center.py +1 -1
  125. dodal/devices/{i24 → beamlines/i24}/beamstop.py +2 -2
  126. dodal/devices/{i24 → beamlines/i24}/commissioning_jungfrau.py +12 -12
  127. dodal/devices/{i24 → beamlines/i24}/dcm.py +1 -3
  128. dodal/devices/{i24 → beamlines/i24}/dual_backlight.py +3 -3
  129. dodal/devices/{i24 → beamlines/i24}/pmac.py +9 -7
  130. dodal/devices/{p60 → beamlines/p60}/lab_xray_source.py +1 -1
  131. dodal/devices/beamlines/p99/__init__.py +0 -0
  132. dodal/devices/{p99 → beamlines/p99}/andor2_point.py +11 -15
  133. dodal/devices/bimorph_mirror.py +22 -20
  134. dodal/devices/collimation_table.py +3 -2
  135. dodal/devices/common_dcm.py +30 -20
  136. dodal/devices/controllers.py +2 -2
  137. dodal/devices/cryostream.py +8 -0
  138. dodal/devices/current_amplifiers/current_amplifier.py +16 -18
  139. dodal/devices/current_amplifiers/current_amplifier_detector.py +9 -10
  140. dodal/devices/current_amplifiers/femto.py +8 -9
  141. dodal/devices/current_amplifiers/sr570.py +16 -16
  142. dodal/devices/current_amplifiers/struck_scaler_counter.py +5 -5
  143. dodal/devices/detector/det_resolution.py +9 -8
  144. dodal/devices/detector/detector.py +4 -2
  145. dodal/devices/diamond_filter.py +3 -4
  146. dodal/devices/eiger.py +32 -17
  147. dodal/devices/eiger_odin.py +1 -1
  148. dodal/devices/electron_analyser/base/__init__.py +3 -3
  149. dodal/devices/electron_analyser/base/base_controller.py +32 -21
  150. dodal/devices/electron_analyser/base/base_detector.py +15 -20
  151. dodal/devices/electron_analyser/base/base_driver_io.py +39 -46
  152. dodal/devices/electron_analyser/base/base_enums.py +0 -5
  153. dodal/devices/electron_analyser/base/base_region.py +29 -31
  154. dodal/devices/electron_analyser/base/base_util.py +18 -16
  155. dodal/devices/electron_analyser/base/energy_sources.py +35 -40
  156. dodal/devices/electron_analyser/specs/specs_detector.py +7 -6
  157. dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py +7 -6
  158. dodal/devices/eurotherm.py +3 -2
  159. dodal/devices/fast_grid_scan.py +31 -34
  160. dodal/devices/fast_shutter.py +125 -39
  161. dodal/devices/flux.py +1 -1
  162. dodal/devices/focusing_mirror.py +29 -11
  163. dodal/devices/hutch_shutter.py +6 -6
  164. dodal/devices/insertion_device/__init__.py +20 -8
  165. dodal/devices/insertion_device/apple2_controller.py +371 -0
  166. dodal/devices/insertion_device/apple2_undulator.py +184 -587
  167. dodal/devices/insertion_device/apple_knot_controller.py +222 -0
  168. dodal/devices/insertion_device/energy.py +161 -0
  169. dodal/devices/insertion_device/energy_motor_lookup.py +21 -28
  170. dodal/devices/insertion_device/lookup_table_models.py +47 -52
  171. dodal/devices/insertion_device/polarisation.py +36 -0
  172. dodal/devices/ipin.py +1 -1
  173. dodal/devices/linkam3.py +7 -5
  174. dodal/devices/motors.py +107 -19
  175. dodal/devices/mx_phase1/beamstop.py +2 -4
  176. dodal/devices/oav/oav_calculations.py +20 -13
  177. dodal/devices/oav/oav_detector.py +92 -22
  178. dodal/devices/oav/oav_parameters.py +4 -9
  179. dodal/devices/oav/oav_to_redis_forwarder.py +22 -18
  180. dodal/devices/oav/pin_image_recognition/__init__.py +4 -6
  181. dodal/devices/oav/pin_image_recognition/manual_test.py +1 -2
  182. dodal/devices/oav/pin_image_recognition/utils.py +30 -32
  183. dodal/devices/oav/snapshots/grid_overlay.py +10 -9
  184. dodal/devices/oav/snapshots/snapshot_image_processing.py +15 -13
  185. dodal/devices/oav/utils.py +20 -6
  186. dodal/devices/p45.py +3 -9
  187. dodal/devices/pgm.py +8 -14
  188. dodal/devices/pressure_jump_cell.py +93 -32
  189. dodal/devices/qbpm.py +1 -3
  190. dodal/devices/robot.py +45 -20
  191. dodal/devices/s4_slit_gaps.py +1 -1
  192. dodal/devices/selectable_source.py +41 -0
  193. dodal/devices/slits.py +2 -5
  194. dodal/devices/smargon.py +2 -3
  195. dodal/devices/temperture_controller/lakeshore/lakeshore.py +38 -64
  196. dodal/devices/temperture_controller/lakeshore/lakeshore_io.py +21 -35
  197. dodal/devices/tetramm.py +7 -7
  198. dodal/devices/turbo_slit.py +8 -7
  199. dodal/devices/undulator.py +42 -56
  200. dodal/devices/util/adjuster_plans.py +2 -3
  201. dodal/devices/util/epics_util.py +10 -10
  202. dodal/devices/util/lookup_tables.py +17 -18
  203. dodal/devices/v2f.py +2 -3
  204. dodal/devices/watsonmarlow323_pump.py +1 -1
  205. dodal/devices/xbpm_feedback.py +3 -2
  206. dodal/devices/xspress3/xspress3.py +8 -11
  207. dodal/devices/xspress3/xspress3_channel.py +3 -6
  208. dodal/devices/zebra/zebra.py +21 -7
  209. dodal/devices/zebra/zebra_constants_mapping.py +12 -7
  210. dodal/devices/zebra/zebra_controlled_shutter.py +2 -1
  211. dodal/devices/zocalo/zocalo_interaction.py +14 -14
  212. dodal/devices/zocalo/zocalo_results.py +33 -33
  213. dodal/log.py +23 -20
  214. dodal/plan_stubs/check_topup.py +15 -15
  215. dodal/plan_stubs/data_session.py +6 -6
  216. dodal/plan_stubs/motor_utils.py +22 -18
  217. dodal/plan_stubs/pressure_jump_cell.py +18 -0
  218. dodal/plan_stubs/wrapped.py +40 -55
  219. dodal/plans/bimorph.py +63 -52
  220. dodal/plans/configure_arm_trigger_and_disarm_detector.py +0 -1
  221. dodal/plans/device_setup_plans/__init__.py +5 -0
  222. dodal/plans/device_setup_plans/setup_pin_tip_params.py +63 -0
  223. dodal/plans/preprocessors/verify_undulator_gap.py +10 -8
  224. dodal/plans/spec_path.py +3 -5
  225. dodal/plans/verify_undulator_gap.py +1 -2
  226. dodal/plans/wrapped.py +4 -3
  227. dodal/testing/__init__.py +0 -0
  228. dodal/testing/electron_analyser/device_factory.py +5 -7
  229. dodal/testing/fixtures/devices/apple2.py +38 -0
  230. dodal/testing/fixtures/run_engine.py +3 -7
  231. dodal/testing/fixtures/utils.py +1 -2
  232. dodal/utils.py +60 -58
  233. dls_dodal-1.68.0.dist-info/RECORD +0 -330
  234. dodal/beamline_specific_utils/i05_shared.py +0 -14
  235. dodal/devices/b07/__init__.py +0 -3
  236. dodal/devices/i04/max_pixel.py +0 -38
  237. dodal/devices/i05/__init__.py +0 -3
  238. dodal/devices/i09/__init__.py +0 -3
  239. dodal/devices/i21/__init__.py +0 -5
  240. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/entry_points.txt +0 -0
  241. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/licenses/LICENSE +0 -0
  242. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/top_level.txt +0 -0
  243. /dodal/{beamline_specific_utils → devices/beamlines}/__init__.py +0 -0
  244. /dodal/devices/{b07 → beamlines/b07}/enums.py +0 -0
  245. /dodal/devices/{b07_1 → beamlines/b07_1}/enums.py +0 -0
  246. /dodal/devices/{b16 → beamlines/b16}/__init__.py +0 -0
  247. /dodal/devices/{i02_1 → beamlines/i02_1}/__init__.py +0 -0
  248. /dodal/devices/{i02_2 → beamlines/i02_2}/__init__.py +0 -0
  249. /dodal/devices/{i03 → beamlines/i03}/__init__.py +0 -0
  250. /dodal/devices/{i03 → beamlines/i03}/constants.py +0 -0
  251. /dodal/devices/{i04 → beamlines/i04}/__init__.py +0 -0
  252. /dodal/devices/{i04 → beamlines/i04}/constants.py +0 -0
  253. /dodal/devices/{i05 → beamlines/i05}/enums.py +0 -0
  254. /dodal/devices/{i07 → beamlines/i07}/__init__.py +0 -0
  255. /dodal/devices/{i09 → beamlines/i09}/enums.py +0 -0
  256. /dodal/devices/{i09_1 → beamlines/i09_1}/__init__.py +0 -0
  257. /dodal/devices/{i09_1 → beamlines/i09_1}/enums.py +0 -0
  258. /dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/__init__.py +0 -0
  259. /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/__init__.py +0 -0
  260. /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/i09_apple2.py +0 -0
  261. /dodal/devices/{i10 → beamlines/i10}/__init__.py +0 -0
  262. /dodal/devices/{i10 → beamlines/i10}/i10_setting_data.py +0 -0
  263. /dodal/devices/{i10 → beamlines/i10}/mirrors.py +0 -0
  264. /dodal/devices/{i10 → beamlines/i10}/rasor/__init__.py +0 -0
  265. /dodal/devices/{i10 → beamlines/i10}/rasor/rasor_scaler_cards.py +0 -0
  266. /dodal/devices/{i11 → beamlines/i10_1/electromagnet}/__init__.py +0 -0
  267. /dodal/devices/{i13_1 → beamlines/i11}/__init__.py +0 -0
  268. /dodal/devices/{i15 → beamlines/i13_1}/__init__.py +0 -0
  269. /dodal/devices/{i13_1 → beamlines/i13_1}/merlin_controller.py +0 -0
  270. /dodal/devices/{i17 → beamlines/i15}/__init__.py +0 -0
  271. /dodal/devices/{i15 → beamlines/i15}/laue.py +0 -0
  272. /dodal/devices/{i15 → beamlines/i15}/motors.py +0 -0
  273. /dodal/devices/{i15 → beamlines/i15}/rail.py +0 -0
  274. /dodal/devices/{i18 → beamlines/i17}/__init__.py +0 -0
  275. /dodal/devices/{i19 → beamlines/i18}/__init__.py +0 -0
  276. /dodal/devices/{i18 → beamlines/i18}/kb_mirror.py +0 -0
  277. /dodal/devices/{i19/access_controlled → beamlines/i19}/__init__.py +0 -0
  278. /dodal/devices/{i20_1 → beamlines/i19/access_controlled}/__init__.py +0 -0
  279. /dodal/devices/{i19 → beamlines/i19}/access_controlled/hutch_access.py +0 -0
  280. /dodal/devices/{i19 → beamlines/i19}/beamstop.py +0 -0
  281. /dodal/devices/{i19 → beamlines/i19}/diffractometer.py +0 -0
  282. /dodal/devices/{i22 → beamlines/i20_1}/__init__.py +0 -0
  283. /dodal/devices/{i21 → beamlines/i21}/enums.py +0 -0
  284. /dodal/devices/{i24 → beamlines/i22}/__init__.py +0 -0
  285. /dodal/devices/{p99 → beamlines/i24}/__init__.py +0 -0
  286. /dodal/devices/{i24 → beamlines/i24}/aperture.py +0 -0
  287. /dodal/devices/{i24 → beamlines/i24}/focus_mirrors.py +0 -0
  288. /dodal/devices/{i24 → beamlines/i24}/vgonio.py +0 -0
  289. /dodal/devices/{p60 → beamlines/p60}/__init__.py +0 -0
  290. /dodal/devices/{p60 → beamlines/p60}/enums.py +0 -0
  291. /dodal/devices/{p99 → beamlines/p99}/sample_stage.py +0 -0
  292. /dodal/devices/insertion_device/{id_enum.py → enum.py} +0 -0
dodal/cli.py CHANGED
@@ -24,6 +24,40 @@ def main(ctx: click.Context) -> None:
24
24
  print("Please invoke subcommand!")
25
25
 
26
26
 
27
+ @main.command(name="describe")
28
+ @click.argument(
29
+ "beamline",
30
+ type=click.Choice(list(all_beamline_names())),
31
+ required=True,
32
+ )
33
+ @click.option("-n", "--name", "device_manager", default="devices")
34
+ def describe(beamline: str, device_manager: str) -> None:
35
+ """Initialises a beamline module, gets the docs of all devices and prints them."""
36
+ os.environ["BEAMLINE"] = beamline
37
+
38
+ module_name = module_name_for_beamline(beamline)
39
+ full_module_path = f"dodal.beamlines.{module_name}"
40
+
41
+ print(f"Analysing {beamline} (using {full_module_path})")
42
+
43
+ mod = importlib.import_module(full_module_path)
44
+
45
+ if (manager := getattr(mod, device_manager, None)) and isinstance(
46
+ manager, DeviceManager
47
+ ):
48
+ factories = manager.get_all_factories()
49
+ else:
50
+ print(
51
+ f"No device manager named '{device_manager}' found in {mod}, convert the beamline to use device manager"
52
+ )
53
+ return
54
+
55
+ for device_name, factory in sorted(factories.items()):
56
+ print(f"{device_name}:")
57
+ print(factory.__doc__)
58
+ print("*****************************************")
59
+
60
+
27
61
  @main.command(name="connect")
28
62
  @click.argument(
29
63
  "beamline",
@@ -48,8 +82,8 @@ def main(ctx: click.Context) -> None:
48
82
  @click.option("-n", "--name", "device_manager", default="devices")
49
83
  def connect(beamline: str, all: bool, sim_backend: bool, device_manager: str) -> None:
50
84
  """Initialises a beamline module, connects to all devices, reports
51
- any connection issues."""
52
-
85
+ any connection issues.
86
+ """
53
87
  os.environ["BEAMLINE"] = beamline
54
88
 
55
89
  # We need to make a fake path provider for any detectors that need one,
dodal/common/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from .coordination import group_uuid, inject
2
2
  from .enums import EnabledDisabledUpper, InOutUpper, OnOffUpper
3
- from .maths import in_micros, step_to_num
3
+ from .maths import Rectangle2D, in_micros, step_to_num
4
4
  from .types import MsgGenerator, PlanGenerator
5
5
 
6
6
  __all__ = [
@@ -13,4 +13,5 @@ __all__ = [
13
13
  "MsgGenerator",
14
14
  "PlanGenerator",
15
15
  "step_to_num",
16
+ "Rectangle2D",
16
17
  ]
@@ -63,7 +63,8 @@ class GDABeamlineParameters:
63
63
 
64
64
  def get_beamline_parameters(beamline_param_path: str | None = None):
65
65
  """Loads the beamline parameters from the specified path, or according to the
66
- environment variable if none is given"""
66
+ environment variable if none is given.
67
+ """
67
68
  if not beamline_param_path:
68
69
  beamline_name = get_beamline_name("i03")
69
70
  beamline_param_path = BEAMLINE_PARAMETER_PATHS.get(beamline_name)
@@ -93,15 +93,17 @@ def device_instantiation(
93
93
  define lists of devices in beamline files. Additional keyword arguments are passed
94
94
  directly to the device constructor.
95
95
 
96
- Arguments:
97
- device_factory: Callable the device class
98
- name: str the name for ophyd
99
- prefix: str the PV prefix for the most (usually all) components
100
- wait: bool whether to run .wait_for_connection()
101
- fake: bool whether to fake with ophyd.sim
102
- post_create: Callable (optional) a function to be run on the device after
103
- creation
104
- bl_prefix: bool if true, add the beamline prefix when instantiating
96
+ Args:
97
+ device_factory (Callable): The device class.
98
+ name (str): The name for ophyd.
99
+ prefix (str): The PV prefix for the most (usually all) components.
100
+ wait (bool): Whether to run .wait_for_connection().
101
+ fake (bool): Whether to fake with ophyd.sim.
102
+ post_create (Callable): (optional) a function to be run on the device after
103
+ creation.
104
+ bl_prefix (bool): If true, add the beamline prefix when instantiating.
105
+ **kwargs: Arguments passed on to every device factory.
106
+
105
107
  Returns:
106
108
  The instance of the device.
107
109
  """
@@ -15,7 +15,8 @@ _commissioning_signal: SignalR | None = None
15
15
  def read_commissioning_mode() -> MsgGenerator[bool]:
16
16
  """Utility method for reading the commissioning mode state from the context
17
17
  of a bluesky plan, where a baton may or may not be present, or
18
- commissioning mode is provided by some other mechanism."""
18
+ commissioning mode is provided by some other mechanism.
19
+ """
19
20
  if _commissioning_signal:
20
21
  return (yield from bps.rd(_commissioning_signal))
21
22
  else:
@@ -26,8 +27,10 @@ def set_commissioning_signal(signal: SignalR[bool] | None):
26
27
  """Commissioning mode is enabled by a PV which when set enables commissioning mode.
27
28
  This allows beamline staff to ensure that commissioning mode is disabled prior
28
29
  to production use, via their own 'good morning' startup scripts.
30
+
29
31
  Args:
30
- signal: The signal which will be read in order to determine whether
31
- commissioning mode is enabled."""
32
+ signal (SignalR): The signal which will be read in order to determine whether
33
+ commissioning mode is enabled.
34
+ """
32
35
  global _commissioning_signal
33
36
  _commissioning_signal = signal
@@ -5,37 +5,35 @@ from dodal.common.types import Group
5
5
 
6
6
 
7
7
  def group_uuid(name: str) -> Group:
8
- """
9
- Returns a unique but human-readable string, to assist debugging orchestrated groups.
8
+ """Returns a unique but human-readable string, to assist debugging orchestrated
9
+ groups.
10
10
 
11
11
  Args:
12
- name (str): A human readable name
12
+ name (str): A human readable name.
13
13
 
14
14
  Returns:
15
- readable_uid (Group): name appended with a unique string
15
+ readable_uid (Group): Name appended with a unique string.
16
16
  """
17
17
  return f"{name}-{str(uuid.uuid4())[:6]}"
18
18
 
19
19
 
20
20
  def inject(name: str = "") -> Any: # type: ignore
21
- """
22
- Function to mark a defaulted argument of a plan as a reference to a device stored
21
+ """Function to mark a defaulted argument of a plan as a reference to a device stored
23
22
  in another context and not available to be referenced directly.
23
+
24
24
  Bypasses type checking, returning x as Any and therefore valid as a default
25
- argument, leaving handling to the context from which the plan is called.
26
- Assumes that device.name is unique.
27
- e.g. For a 1-dimensional scan, that is usually performed on a Movable with
28
- name "stage_x"
25
+ argument, leaving handling to the context from which the plan is called. Assumes
26
+ that device.name is unique. e.g. For a 1-dimensional scan, that is usually performed
27
+ on a Movable with name "stage_x"::
29
28
 
30
- def scan(x: Movable = inject("stage_x"), start: float = 0.0 ...)
29
+ def scan(x: Movable = inject("stage_x"), start: float = 0.0 ...)
31
30
 
32
31
  Args:
33
32
  name (str): Name of a Device to be fetched from an external context. This can be
34
- left blank when injecting device composites (the default)
33
+ left blank when injecting device composites (the default).
35
34
 
36
35
  Returns:
37
- Any: name but without typing checking, valid as any default type
36
+ Any: Name but without typing checking, valid as any default type.
38
37
 
39
38
  """
40
-
41
39
  return name
@@ -6,9 +6,7 @@ from typing import Literal
6
6
 
7
7
  @dataclass(frozen=True)
8
8
  class Material:
9
- """
10
- Class representing a crystalline material with a specific lattice parameter.
11
- """
9
+ """Class representing a crystalline material with a specific lattice parameter."""
12
10
 
13
11
  name: str
14
12
  lattice_parameter: float # Lattice parameter in meters
@@ -21,9 +19,8 @@ class MaterialsEnum(Enum):
21
19
 
22
20
  @dataclass(frozen=True)
23
21
  class CrystalMetadata:
24
- """
25
- Metadata used in the NeXus format,
26
- see https://manual.nexusformat.org/classes/base_classes/NXcrystal.html
22
+ """Metadata used in the NeXus format,
23
+ see https://manual.nexusformat.org/classes/base_classes/NXcrystal.html.
27
24
  """
28
25
 
29
26
  usage: Literal["Bragg", "Laue"]
@@ -35,8 +32,8 @@ class CrystalMetadata:
35
32
  def calculate_default_d_spacing(
36
33
  lattice_parameter: float, reflection: tuple[int, int, int]
37
34
  ) -> tuple[float, str]:
38
- """
39
- Calculates the d-spacing value in nanometers based on the given lattice parameter and reflection indices.
35
+ """Calculates the d-spacing value in nanometers based on the given lattice
36
+ parameter and reflection indices.
40
37
  """
41
38
  h_index, k_index, l_index = reflection
42
39
  d_spacing_m = lattice_parameter / math.sqrt(
@@ -19,11 +19,12 @@ async def periodic_reminder(
19
19
  """Periodically logs a message according to a schedule with increasing delays.
20
20
 
21
21
  Args:
22
- message: The message the user wants to output through logging.
23
- schedule: A tuple list of tuples consisting of (int|float, int|None).
22
+ message (str): The message the user wants to output through logging.
23
+ schedule (tuple): A tuple list of tuples consisting of (int|float, int|None).
24
24
  A sequence of (delay_seconds, count) pairs defining the logging intervals.
25
25
  - delay_seconds is the number of seconds to wait between logs.
26
- - count is how many times to log at this interval. If count is None, it logs indefinitely at that delay.
26
+ - count is how many times to log at this interval. If count is None, it logs
27
+ indefinitely at that delay.
27
28
  """
28
29
 
29
30
  async def _log_loop():
dodal/common/maths.py CHANGED
@@ -2,28 +2,24 @@ import numpy as np
2
2
 
3
3
 
4
4
  def step_to_num(start: float, stop: float, step: float) -> tuple[float, float, int]:
5
- """
6
- Standard handling for converting from start, stop, step to start, stop, num
7
- Forces step to be same direction as length
5
+ """Standard handling for converting from start, stop, step to start, stop, num.
6
+ Forces step to be same direction as length.
8
7
  Includes a final point if it is within 1% of the final step, prevents floating
9
8
  point arithmatic errors from giving inconsistent shaped scans between steps of an
10
9
  outer axis.
11
10
 
12
11
  Args:
13
- start (float):
14
- Start of length, will be returned unchanged
15
- stop (float):
16
- End of length, if length/step does not divide cleanly will be returned
17
- extended up to 1% of step, or else truncated.
18
- step (float):
19
- Length of a step along the line formed from start to stop.
20
- If stop < start, will be coerced to be backwards.
12
+ start (float): Start of length, will be returned unchanged.
13
+ stop (float): End of length, if length/step does not divide cleanly will be
14
+ returned extended up to 1% of step, or else truncated.
15
+ step (float): Length of a step along the line formed from start to stop. If
16
+ stop < start, will be coerced to be backwards.
21
17
 
22
18
  Returns:
23
19
  start, adjusted_stop, num = Tuple[float, float, int]
24
- start will be returned unchanged
25
- adjusted_stop = start + (num - 1) * step
26
- num is the maximal number of steps that could fit into the length.
20
+ - start will be returned unchanged.
21
+ - adjusted_stop = start + (num - 1) * step.
22
+ - num is the maximal number of steps that could fit into the length.
27
23
 
28
24
  """
29
25
  # Make step be the right direction
@@ -34,17 +30,89 @@ def step_to_num(start: float, stop: float, step: float) -> tuple[float, float, i
34
30
 
35
31
 
36
32
  def in_micros(t: float) -> int:
37
- """
38
- Converts between a positive number of seconds and an equivalent
33
+ """Converts between a positive number of seconds and an equivalent
39
34
  number of microseconds.
40
35
 
41
36
  Args:
42
- t (float): A time in seconds
37
+ t (float): A time in seconds.
38
+
43
39
  Raises:
44
- ValueError: if t < 0
40
+ ValueError: if t < 0.
41
+
45
42
  Returns:
46
- t (int): A time in microseconds, rounded up to the nearest whole microsecond,
43
+ int: A time in microseconds, rounded up to the nearest whole microsecond.
47
44
  """
48
45
  if t < 0:
49
46
  raise ValueError(f"Expected a positive time in seconds, got {t!r}")
50
47
  return int(np.ceil(t * 1e6))
48
+
49
+
50
+ class Rectangle2D:
51
+ """A 2D rectangle defined by two opposite corners.
52
+
53
+ This class represents a rectangle in 2D space using two points: (x1, y1) and (x2, y2).
54
+ It provides methods to query rectangle properties and check point containment.
55
+
56
+ Attributes:
57
+ x1 (float): The x-coordinate of the first corner.
58
+ y1 (float): The y-coordinate of the first corner.
59
+ x2 (float): The x-coordinate of the second corner.
60
+ y2 (float): The y-coordinate of the second corner.
61
+
62
+ Args:
63
+ x1 (float): The x-coordinate of the first corner.
64
+ y1 (float): The y-coordinate of the first corner.
65
+ x2 (float): The x-coordinate of the second corner.
66
+ y2 (float): The y-coordinate of the second corner.
67
+ """
68
+
69
+ def __init__(self, x1: float, y1: float, x2: float, y2: float):
70
+ self.x1, self.y1 = x1, y1
71
+ self.x2, self.y2 = x2, y2
72
+
73
+ def get_max_x(self) -> float:
74
+ """Get the maximum x-coordinate of the rectangle.
75
+
76
+ Returns:
77
+ float: The larger of the two x-coordinates (x1, x2).
78
+ """
79
+ return max(self.x1, self.x2)
80
+
81
+ def get_min_x(self) -> float:
82
+ """Get the minimum x-coordinate of the rectangle.
83
+
84
+ Returns:
85
+ float: The smaller of the two x-coordinates (x1, x2).
86
+ """
87
+ return min(self.x1, self.x2)
88
+
89
+ def get_max_y(self) -> float:
90
+ """Get the maximum y-coordinate of the rectangle.
91
+
92
+ Returns:
93
+ float: The larger of the two y-coordinates (y1, y2).
94
+ """
95
+ return max(self.y1, self.y2)
96
+
97
+ def get_min_y(self) -> float:
98
+ """Get the minimum y-coordinate of the rectangle.
99
+
100
+ Returns:
101
+ float: The smaller of the two y-coordinates (y1, y2).
102
+ """
103
+ return min(self.y1, self.y2)
104
+
105
+ def contains(self, x: float, y: float) -> bool:
106
+ """Check if a point is contained within the rectangle.
107
+
108
+ Args:
109
+ x (float): The x-coordinate of the point.
110
+ y (float): The y-coordinate of the point.
111
+
112
+ Returns:
113
+ bool: True if the point is within the rectangle bounds, False otherwise.
114
+ """
115
+ return (
116
+ self.get_min_x() <= x <= self.get_max_x()
117
+ and self.get_min_y() <= y <= self.get_max_y()
118
+ )
@@ -16,7 +16,8 @@ class PandAFilenameProvider(FilenameProvider):
16
16
 
17
17
  class PandASubpathProvider(UpdatingPathProvider):
18
18
  """Directory provider for the HDFPanda. Points to a panda subdirectory within the
19
- directory path provided"""
19
+ directory path provided.
20
+ """
20
21
 
21
22
  resource_dir = Path("panda")
22
23
 
@@ -34,13 +35,17 @@ class PandASubpathProvider(UpdatingPathProvider):
34
35
  return self._filename_provider.suffix or ""
35
36
 
36
37
  async def update(self, *, directory: Path, suffix: str = "", **kwargs):
37
- """Update the root directory into which panda pcap files are written. This will result in the panda
38
- subdirectory being created if it does not already exist.
39
- Args:
40
- directory: Path instance that identifies the root folder. This folder must exist. The panda will
41
- attempt to write into the "panda" subdirectory which will be created if not already present.
42
- suffix: Optional str that will be appended to the panda device name along with the file
43
- type extension to construct the output filename
38
+ """Update the root directory into which panda pcap files are written. This will
39
+ result in the panda subdirectory being created if it does not already exist.
40
+
41
+ Args:
42
+ directory (Path): Instance that identifies the root folder. This folder must
43
+ exist. The panda will attempt to write into the "panda" subdirectory
44
+ which will be created if not already present.
45
+ suffix (str, optional): Optional str that will be appended to the panda
46
+ device name along with the file type extension to construct the output
47
+ filename.
48
+ **kwargs: Seemingly unused.
44
49
  """
45
50
  self._output_directory = directory / self.resource_dir
46
51
  self._filename_provider.suffix = suffix
dodal/common/visit.py CHANGED
@@ -9,32 +9,29 @@ from pydantic import BaseModel, Field
9
9
  from dodal.common.types import UpdatingPathProvider
10
10
  from dodal.log import LOGGER
11
11
 
12
- """
13
- Functionality required for/from the API of a DirectoryService which exposes the specifics of the Diamond filesystem.
14
- """
12
+ """Functionality required for/from the API of a DirectoryService which exposes the
13
+ specifics of the Diamond filesystem."""
15
14
 
16
15
 
17
16
  class DataCollectionIdentifier(BaseModel):
18
- """
19
- Equivalent to a `Scan Number` or `scan_id`, non-globally unique scan identifier.
20
- Should be always incrementing, unique per-visit, co-ordinated with any other scan engines.
17
+ """Equivalent to a `Scan Number` or `scan_id`, non-globally unique scan identifier.
18
+ Should be always incrementing, unique per-visit, co-ordinated with any other scan
19
+ engines.
21
20
  """
22
21
 
23
22
  collection_number: int = Field(alias="collectionNumber")
24
23
 
25
24
 
26
25
  class DirectoryServiceClient(ABC):
27
- """
28
- Object responsible for I/O in determining collection number
29
- """
26
+ """Object responsible for I/O in determining collection number."""
30
27
 
31
28
  @abstractmethod
32
29
  async def create_new_collection(self) -> DataCollectionIdentifier:
33
- """Create new collection"""
30
+ """Create new collection."""
34
31
 
35
32
  @abstractmethod
36
33
  async def get_current_collection(self) -> DataCollectionIdentifier:
37
- """Get current collection"""
34
+ """Get current collection."""
38
35
 
39
36
 
40
37
  class DiamondFilenameProvider(FilenameProvider):
@@ -50,9 +47,9 @@ class DiamondFilenameProvider(FilenameProvider):
50
47
 
51
48
 
52
49
  class RemoteDirectoryServiceClient(DirectoryServiceClient):
53
- """Client for the VisitService REST API
50
+ """Client for the VisitService REST API.
54
51
  Currently exposed by the GDA Server to co-ordinate unique filenames.
55
- While VisitService is embedded in GDA, url is likely to be `ixx-control:8088/api`
52
+ While VisitService is embedded in GDA, url is likely to be `ixx-control:8088/api`.
56
53
  """
57
54
 
58
55
  def __init__(self, url: str) -> None:
@@ -98,13 +95,15 @@ class LocalDirectoryServiceClient(DirectoryServiceClient):
98
95
 
99
96
 
100
97
  class StaticVisitPathProvider(UpdatingPathProvider):
101
- """
102
- Static (single visit) implementation of PathProvider whilst awaiting auth infrastructure to generate necessary information per-scan.
98
+ """Static (single visit) implementation of PathProvider whilst awaiting auth
99
+ infrastructure to generate necessary information per-scan.
103
100
  Allows setting a singular visit into which all run files will be saved.
104
- update() queries a visit service to get the next DataCollectionIdentifier to increment the suffix of all file writers' next files.
101
+ update() queries a visit service to get the next DataCollectionIdentifier to
102
+ increment the suffix of all file writers' next files.
105
103
  Requires that all detectors are running with a mutual view on the filesystem.
106
- Supports a single Visit which should be passed as a Path relative to the root of the Detector IOC mounting.
107
- i.e. to write to visit /dls/ixx/data/YYYY/cm12345-1
104
+ Supports a single Visit which should be passed as a Path relative to the root of
105
+ the Detector IOC mounting.
106
+ i.e. to write to visit `/dls/ixx/data/YYYY/cm12345-1`.
108
107
  """
109
108
 
110
109
  def __init__(
@@ -123,9 +122,7 @@ class StaticVisitPathProvider(UpdatingPathProvider):
123
122
  self._session: ClientSession | None
124
123
 
125
124
  async def update(self, **kwargs) -> None:
126
- """
127
- Creates a new data collection in the current visit.
128
- """
125
+ """Creates a new data collection in the current visit."""
129
126
  # https://github.com/DiamondLightSource/dodal/issues/452
130
127
  # TODO: Allow selecting visit as part of a request
131
128
  # TODO: DAQ-4827: Pass AuthN information as part of request
@@ -55,22 +55,24 @@ def log_on_percentage_complete(
55
55
  message_prefix: str,
56
56
  percent_interval: int = 25,
57
57
  ):
58
- """
59
- Add watcher to a WatchableAsyncStatus status which will periodically log a message based on percentage completion
58
+ """Add watcher to a WatchableAsyncStatus status which will periodically log a
59
+ message based on percentage completion.
60
60
 
61
61
  Args:
62
- status: A WatchableAsyncStatus. For example, Ophyd-async produces this status from a Motor.set method
63
-
64
- message_prefix: The string at the start of each of the produced logging messages
65
-
66
- percent_interval: How often to produce logging message, in terms of percentage completion
67
- of the status.
62
+ status (WatchableAsyncStatus): For example, Ophyd-async produces this status
63
+ from a Motor.set method.
64
+ message_prefix (str): The string at the start of each of the produced logging
65
+ messages
66
+ percent_interval (int, optional): How often to produce logging message, in
67
+ terms of percentage completion of the status.
68
68
 
69
69
  Note that when using with Bluesky plan stubs you will need to cast the status (as of
70
- Bluesky v1.14.2), since a Bluesky status doesn't use generics - see https://github.com/bluesky/bluesky/issues/1948.
70
+ Bluesky v1.14.2), since a Bluesky status doesn't use generics - see
71
+ https://github.com/bluesky/bluesky/issues/1948.
71
72
 
72
- When running Bluesky plans using an interactive terminal, it is better to use the standard bluesky progress
73
- bar instead of this function. See https://blueskyproject.io/bluesky/main/progress-bar.html#progress-bar
73
+ When running Bluesky plans using an interactive terminal, it is better to use the
74
+ standard bluesky progress bar instead of this function. See
75
+ https://blueskyproject.io/bluesky/main/progress-bar.html#progress-bar.
74
76
 
75
77
  Example usage within a Bluesky plan:
76
78
  yield from bps.kickoff(my_detector)
@@ -78,6 +80,5 @@ def log_on_percentage_complete(
78
80
  status = cast(WatchableAsyncStatus, status)
79
81
  log_on_percentage_complete(status, "Data collection triggers received", 10)
80
82
  yield from bps.wait("collection complete")
81
-
82
83
  """
83
84
  _LogOnPercentageProgressWatcher(status, message_prefix, percent_interval)