dls-dodal 1.38.0__py3-none-any.whl → 1.40.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 (49) hide show
  1. {dls_dodal-1.38.0.dist-info → dls_dodal-1.40.0.dist-info}/METADATA +2 -2
  2. {dls_dodal-1.38.0.dist-info → dls_dodal-1.40.0.dist-info}/RECORD +49 -40
  3. dodal/_version.py +2 -2
  4. dodal/beamlines/__init__.py +2 -0
  5. dodal/beamlines/adsim.py +3 -2
  6. dodal/beamlines/b01_1.py +3 -3
  7. dodal/beamlines/i03.py +144 -285
  8. dodal/beamlines/i04.py +112 -198
  9. dodal/beamlines/i13_1.py +5 -4
  10. dodal/beamlines/i18.py +124 -0
  11. dodal/beamlines/i19_1.py +74 -0
  12. dodal/beamlines/i19_2.py +61 -0
  13. dodal/beamlines/i20_1.py +37 -22
  14. dodal/beamlines/i22.py +7 -7
  15. dodal/beamlines/i24.py +100 -145
  16. dodal/beamlines/p38.py +12 -8
  17. dodal/beamlines/p45.py +5 -4
  18. dodal/beamlines/training_rig.py +4 -4
  19. dodal/common/beamlines/beamline_utils.py +2 -3
  20. dodal/common/beamlines/device_helpers.py +3 -1
  21. dodal/devices/aperturescatterguard.py +150 -64
  22. dodal/devices/apple2_undulator.py +86 -113
  23. dodal/devices/eiger.py +24 -14
  24. dodal/devices/fast_grid_scan.py +29 -20
  25. dodal/devices/hutch_shutter.py +25 -12
  26. dodal/devices/i04/transfocator.py +22 -29
  27. dodal/devices/i10/rasor/rasor_scaler_cards.py +4 -4
  28. dodal/devices/i13_1/merlin.py +4 -3
  29. dodal/devices/i13_1/merlin_controller.py +2 -7
  30. dodal/devices/i18/KBMirror.py +19 -0
  31. dodal/devices/i18/diode.py +17 -0
  32. dodal/devices/i18/table.py +14 -0
  33. dodal/devices/i18/thor_labs_stage.py +12 -0
  34. dodal/devices/i19/__init__.py +0 -0
  35. dodal/devices/i19/shutter.py +57 -0
  36. dodal/devices/i22/nxsas.py +4 -4
  37. dodal/devices/motors.py +2 -2
  38. dodal/devices/oav/oav_detector.py +10 -19
  39. dodal/devices/pressure_jump_cell.py +33 -16
  40. dodal/devices/robot.py +30 -11
  41. dodal/devices/tetramm.py +8 -3
  42. dodal/devices/turbo_slit.py +7 -6
  43. dodal/devices/zocalo/zocalo_results.py +21 -4
  44. dodal/plans/save_panda.py +30 -14
  45. dodal/utils.py +54 -15
  46. {dls_dodal-1.38.0.dist-info → dls_dodal-1.40.0.dist-info}/LICENSE +0 -0
  47. {dls_dodal-1.38.0.dist-info → dls_dodal-1.40.0.dist-info}/WHEEL +0 -0
  48. {dls_dodal-1.38.0.dist-info → dls_dodal-1.40.0.dist-info}/entry_points.txt +0 -0
  49. {dls_dodal-1.38.0.dist-info → dls_dodal-1.40.0.dist-info}/top_level.txt +0 -0
dodal/utils.py CHANGED
@@ -102,7 +102,7 @@ class BeamlinePrefix:
102
102
 
103
103
 
104
104
  T = TypeVar("T", bound=AnyDevice)
105
- D = TypeVar("D", bound=OphydV2Device)
105
+
106
106
  SkipType = bool | Callable[[], bool]
107
107
 
108
108
 
@@ -119,16 +119,16 @@ def skip_device(precondition=lambda: True):
119
119
  return decorator
120
120
 
121
121
 
122
- class DeviceInitializationController(Generic[D]):
122
+ class DeviceInitializationController(Generic[T]):
123
123
  def __init__(
124
124
  self,
125
- factory: Callable[[], D],
125
+ factory: Callable[[], T],
126
126
  use_factory_name: bool,
127
127
  timeout: float,
128
128
  mock: bool,
129
129
  skip: SkipType,
130
130
  ):
131
- self._factory: Callable[[], D] = functools.cache(factory)
131
+ self._factory: Callable[..., T] = functools.cache(factory)
132
132
  self._use_factory_name = use_factory_name
133
133
  self._timeout = timeout
134
134
  self._mock = mock
@@ -153,13 +153,15 @@ class DeviceInitializationController(Generic[D]):
153
153
  name: str | None = None,
154
154
  connection_timeout: float | None = None,
155
155
  mock: bool | None = None,
156
- ) -> D:
156
+ **kwargs,
157
+ ) -> T:
157
158
  """Returns an instance of the Device the wrapped factory produces: the same
158
159
  instance will be returned if this method is called multiple times, and arguments
159
160
  may be passed to override this Controller's configuration.
160
161
  Once the device is connected, the value of mock must be consistent, or connect
161
162
  must be False.
162
163
 
164
+ Additional keyword arguments will be passed through to the wrapped factory function.
163
165
 
164
166
  Args:
165
167
  connect_immediately (bool, default False): whether to call connect on the
@@ -182,19 +184,36 @@ class DeviceInitializationController(Generic[D]):
182
184
  connect is called on the Device.
183
185
 
184
186
  Returns:
185
- D: a singleton instance of the Device class returned by the wrapped factory.
187
+ T: a singleton instance of the Device class returned by the wrapped factory.
188
+
189
+ Raises:
190
+ RuntimeError: If the device factory was invoked again with different
191
+ keyword arguments, without previously invoking cache_clear()
186
192
  """
187
- device = self._factory()
193
+ is_v2_device = is_v2_device_factory(self._factory)
194
+ is_mock = mock if mock is not None else self._mock
195
+ if is_v2_device:
196
+ device: T = self._factory(**kwargs)
197
+ else:
198
+ device: T = self._factory(mock=is_mock, **kwargs)
199
+
200
+ if self._factory.cache_info().currsize > 1: # type: ignore
201
+ raise RuntimeError(
202
+ f"Device factory method called multiple times with different parameters: "
203
+ f"{self.__name__}" # type: ignore
204
+ )
188
205
 
189
206
  if connect_immediately:
190
- call_in_bluesky_event_loop(
191
- device.connect(
192
- timeout=connection_timeout
193
- if connection_timeout is not None
194
- else self._timeout,
195
- mock=mock if mock is not None else self._mock,
196
- )
207
+ timeout = (
208
+ connection_timeout if connection_timeout is not None else self._timeout
197
209
  )
210
+ if is_v2_device:
211
+ call_in_bluesky_event_loop(
212
+ device.connect(timeout=timeout, mock=is_mock)
213
+ )
214
+ else:
215
+ assert is_v1_device_type(type(device))
216
+ device.wait_for_connection(timeout=timeout) # type: ignore
198
217
 
199
218
  if name:
200
219
  device.set_name(name)
@@ -410,7 +429,27 @@ def is_any_device_factory(func: Callable) -> TypeGuard[AnyDeviceFactory]:
410
429
 
411
430
 
412
431
  def is_v2_device_type(obj: type[Any]) -> bool:
413
- return inspect.isclass(obj) and isinstance(obj, OphydV2Device)
432
+ non_parameterized_class = None
433
+ if obj != inspect.Signature.empty:
434
+ if inspect.isclass(obj):
435
+ non_parameterized_class = obj
436
+ elif hasattr(obj, "__origin__"):
437
+ # typing._GenericAlias is the same as types.GenericAlias, maybe?
438
+ # This is all very badly documented and possibly prone to change in future versions of Python
439
+ non_parameterized_class = obj.__origin__
440
+ if non_parameterized_class:
441
+ try:
442
+ return non_parameterized_class and issubclass(
443
+ non_parameterized_class, OphydV2Device
444
+ )
445
+ except TypeError:
446
+ # Python 3.10 will return inspect.isclass(t) == True but then
447
+ # raise TypeError: issubclass() arg 1 must be a class
448
+ # when inspecting device_factory decorator function itself
449
+ # Later versions of Python seem not to be affected
450
+ pass
451
+
452
+ return False
414
453
 
415
454
 
416
455
  def is_v1_device_type(obj: type[Any]) -> bool: