ophyd-async 0.5.1__py3-none-any.whl → 0.6.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 (73) hide show
  1. ophyd_async/__init__.py +10 -1
  2. ophyd_async/__main__.py +12 -4
  3. ophyd_async/_version.py +2 -2
  4. ophyd_async/core/__init__.py +15 -6
  5. ophyd_async/core/_detector.py +72 -63
  6. ophyd_async/core/_device.py +13 -15
  7. ophyd_async/core/_device_save_loader.py +30 -19
  8. ophyd_async/core/_flyer.py +6 -4
  9. ophyd_async/core/_hdf_dataset.py +8 -9
  10. ophyd_async/core/_log.py +3 -1
  11. ophyd_async/core/_mock_signal_backend.py +11 -9
  12. ophyd_async/core/_mock_signal_utils.py +8 -5
  13. ophyd_async/core/_protocol.py +7 -7
  14. ophyd_async/core/_providers.py +17 -13
  15. ophyd_async/core/_readable.py +30 -22
  16. ophyd_async/core/_signal.py +53 -52
  17. ophyd_async/core/_signal_backend.py +20 -7
  18. ophyd_async/core/_soft_signal_backend.py +62 -32
  19. ophyd_async/core/_status.py +18 -4
  20. ophyd_async/core/_table.py +63 -0
  21. ophyd_async/core/_utils.py +24 -28
  22. ophyd_async/epics/adaravis/_aravis.py +1 -1
  23. ophyd_async/epics/adaravis/_aravis_controller.py +17 -16
  24. ophyd_async/epics/adaravis/_aravis_io.py +2 -1
  25. ophyd_async/epics/adcore/__init__.py +2 -2
  26. ophyd_async/epics/adcore/_core_io.py +2 -0
  27. ophyd_async/epics/adcore/_core_logic.py +9 -7
  28. ophyd_async/epics/adcore/_hdf_writer.py +26 -21
  29. ophyd_async/epics/adcore/_single_trigger.py +1 -1
  30. ophyd_async/epics/adcore/_utils.py +5 -6
  31. ophyd_async/epics/adkinetix/_kinetix.py +1 -1
  32. ophyd_async/epics/adkinetix/_kinetix_controller.py +19 -14
  33. ophyd_async/epics/adpilatus/_pilatus.py +1 -1
  34. ophyd_async/epics/adpilatus/_pilatus_controller.py +18 -16
  35. ophyd_async/epics/adsimdetector/_sim.py +7 -6
  36. ophyd_async/epics/adsimdetector/_sim_controller.py +20 -15
  37. ophyd_async/epics/advimba/_vimba.py +1 -1
  38. ophyd_async/epics/advimba/_vimba_controller.py +21 -16
  39. ophyd_async/epics/demo/_mover.py +4 -5
  40. ophyd_async/epics/demo/sensor.db +0 -1
  41. ophyd_async/epics/eiger/__init__.py +5 -0
  42. ophyd_async/epics/eiger/_eiger.py +43 -0
  43. ophyd_async/epics/eiger/_eiger_controller.py +66 -0
  44. ophyd_async/epics/eiger/_eiger_io.py +42 -0
  45. ophyd_async/epics/eiger/_odin_io.py +126 -0
  46. ophyd_async/epics/motor.py +9 -11
  47. ophyd_async/epics/pvi/_pvi.py +30 -33
  48. ophyd_async/epics/signal/_aioca.py +55 -25
  49. ophyd_async/epics/signal/_common.py +3 -10
  50. ophyd_async/epics/signal/_epics_transport.py +11 -8
  51. ophyd_async/epics/signal/_p4p.py +79 -30
  52. ophyd_async/epics/signal/_signal.py +6 -8
  53. ophyd_async/fastcs/panda/__init__.py +0 -6
  54. ophyd_async/fastcs/panda/_control.py +14 -15
  55. ophyd_async/fastcs/panda/_hdf_panda.py +11 -4
  56. ophyd_async/fastcs/panda/_table.py +111 -138
  57. ophyd_async/fastcs/panda/_trigger.py +1 -2
  58. ophyd_async/fastcs/panda/_utils.py +3 -2
  59. ophyd_async/fastcs/panda/_writer.py +28 -13
  60. ophyd_async/plan_stubs/_fly.py +16 -16
  61. ophyd_async/plan_stubs/_nd_attributes.py +12 -6
  62. ophyd_async/sim/demo/_pattern_detector/_pattern_detector.py +3 -3
  63. ophyd_async/sim/demo/_pattern_detector/_pattern_detector_controller.py +24 -20
  64. ophyd_async/sim/demo/_pattern_detector/_pattern_detector_writer.py +9 -6
  65. ophyd_async/sim/demo/_pattern_detector/_pattern_generator.py +21 -23
  66. ophyd_async/sim/demo/_sim_motor.py +2 -1
  67. {ophyd_async-0.5.1.dist-info → ophyd_async-0.6.0.dist-info}/METADATA +46 -45
  68. ophyd_async-0.6.0.dist-info/RECORD +96 -0
  69. {ophyd_async-0.5.1.dist-info → ophyd_async-0.6.0.dist-info}/WHEEL +1 -1
  70. ophyd_async-0.5.1.dist-info/RECORD +0 -90
  71. {ophyd_async-0.5.1.dist-info → ophyd_async-0.6.0.dist-info}/LICENSE +0 -0
  72. {ophyd_async-0.5.1.dist-info → ophyd_async-0.6.0.dist-info}/entry_points.txt +0 -0
  73. {ophyd_async-0.5.1.dist-info → ophyd_async-0.6.0.dist-info}/top_level.txt +0 -0
@@ -3,14 +3,19 @@ import atexit
3
3
  import inspect
4
4
  import logging
5
5
  import time
6
+ from collections.abc import Sequence
6
7
  from dataclasses import dataclass
7
8
  from enum import Enum
8
9
  from math import isnan, nan
9
- from typing import Any, Dict, List, Optional, Sequence, Type, Union
10
+ from typing import Any, get_origin
10
11
 
11
- from bluesky.protocols import DataKey, Dtype, Reading
12
+ import numpy as np
13
+ from bluesky.protocols import Reading
14
+ from event_model import DataKey
15
+ from event_model.documents.event_descriptor import Dtype
12
16
  from p4p import Value
13
17
  from p4p.client.asyncio import Context, Subscription
18
+ from pydantic import BaseModel
14
19
 
15
20
  from ophyd_async.core import (
16
21
  DEFAULT_TIMEOUT,
@@ -21,13 +26,14 @@ from ophyd_async.core import (
21
26
  T,
22
27
  get_dtype,
23
28
  get_unique,
29
+ is_pydantic_model,
24
30
  wait_for_connection,
25
31
  )
26
32
 
27
33
  from ._common import LimitPair, Limits, common_meta, get_supported_values
28
34
 
29
35
  # https://mdavidsaver.github.io/p4p/values.html
30
- specifier_to_dtype: Dict[str, Dtype] = {
36
+ specifier_to_dtype: dict[str, Dtype] = {
31
37
  "?": "integer", # bool
32
38
  "b": "integer", # int8
33
39
  "B": "integer", # uint8
@@ -42,7 +48,7 @@ specifier_to_dtype: Dict[str, Dtype] = {
42
48
  "s": "string",
43
49
  }
44
50
 
45
- specifier_to_np_dtype: Dict[str, str] = {
51
+ specifier_to_np_dtype: dict[str, str] = {
46
52
  "?": "<i2", # bool
47
53
  "b": "|i1", # int8
48
54
  "B": "|u1", # uint8
@@ -62,9 +68,9 @@ def _data_key_from_value(
62
68
  source: str,
63
69
  value: Value,
64
70
  *,
65
- shape: Optional[list[int]] = None,
66
- choices: Optional[list[str]] = None,
67
- dtype: Optional[Dtype] = None,
71
+ shape: list[int] | None = None,
72
+ choices: list[str] | None = None,
73
+ dtype: Dtype | None = None,
68
74
  ) -> DataKey:
69
75
  """
70
76
  Args:
@@ -105,7 +111,8 @@ def _data_key_from_value(
105
111
  d = DataKey(
106
112
  source=source,
107
113
  dtype=dtype,
108
- dtype_numpy=dtype_numpy,
114
+ # type ignore until https://github.com/bluesky/event-model/issues/308
115
+ dtype_numpy=dtype_numpy, # type: ignore
109
116
  shape=shape,
110
117
  )
111
118
  if display_data is not None:
@@ -115,10 +122,12 @@ def _data_key_from_value(
115
122
  d[key] = attr
116
123
 
117
124
  if choices is not None:
118
- d["choices"] = choices
125
+ # type ignore until https://github.com/bluesky/event-model/issues/309
126
+ d["choices"] = choices # type: ignore
119
127
 
120
128
  if limits := _limits_from_value(value):
121
- d["limits"] = limits
129
+ # type ignore until https://github.com/bluesky/event-model/issues/309
130
+ d["limits"] = limits # type: ignore
122
131
 
123
132
  return d
124
133
 
@@ -149,7 +158,7 @@ class PvaConverter:
149
158
  def value(self, value):
150
159
  return value["value"]
151
160
 
152
- def reading(self, value):
161
+ def reading(self, value) -> Reading:
153
162
  ts = value["timeStamp"]
154
163
  sv = value["alarm"]["severity"]
155
164
  return {
@@ -161,13 +170,13 @@ class PvaConverter:
161
170
  def get_datakey(self, source: str, value) -> DataKey:
162
171
  return _data_key_from_value(source, value)
163
172
 
164
- def metadata_fields(self) -> List[str]:
173
+ def metadata_fields(self) -> list[str]:
165
174
  """
166
175
  Fields to request from PVA for metadata.
167
176
  """
168
177
  return ["alarm", "timeStamp"]
169
178
 
170
- def value_fields(self) -> List[str]:
179
+ def value_fields(self) -> list[str]:
171
180
  """
172
181
  Fields to request from PVA for the value.
173
182
  """
@@ -182,11 +191,11 @@ class PvaArrayConverter(PvaConverter):
182
191
 
183
192
 
184
193
  class PvaNDArrayConverter(PvaConverter):
185
- def metadata_fields(self) -> List[str]:
194
+ def metadata_fields(self) -> list[str]:
186
195
  return super().metadata_fields() + ["dimension"]
187
196
 
188
- def _get_dimensions(self, value) -> List[int]:
189
- dimensions: List[Value] = value["dimension"]
197
+ def _get_dimensions(self, value) -> list[int]:
198
+ dimensions: list[Value] = value["dimension"]
190
199
  dims = [dim.size for dim in dimensions]
191
200
  # Note: dimensions in NTNDArray are in fortran-like order
192
201
  # with first index changing fastest.
@@ -221,7 +230,7 @@ class PvaEnumConverter(PvaConverter):
221
230
  def __init__(self, choices: dict[str, str]):
222
231
  self.choices = tuple(choices.values())
223
232
 
224
- def write_value(self, value: Union[Enum, str]):
233
+ def write_value(self, value: Enum | str):
225
234
  if isinstance(value, Enum):
226
235
  return value.value
227
236
  else:
@@ -250,11 +259,24 @@ class PvaTableConverter(PvaConverter):
250
259
 
251
260
  def get_datakey(self, source: str, value) -> DataKey:
252
261
  # This is wrong, but defer until we know how to actually describe a table
253
- return _data_key_from_value(source, value, dtype="object")
262
+ return _data_key_from_value(source, value, dtype="object") # type: ignore
263
+
264
+
265
+ class PvaPydanticModelConverter(PvaConverter):
266
+ def __init__(self, datatype: BaseModel):
267
+ self.datatype = datatype
268
+
269
+ def value(self, value: Value):
270
+ return self.datatype(**value.todict()) # type: ignore
271
+
272
+ def write_value(self, value: BaseModel | dict[str, Any]):
273
+ if isinstance(value, self.datatype): # type: ignore
274
+ return value.model_dump(mode="python") # type: ignore
275
+ return value
254
276
 
255
277
 
256
278
  class PvaDictConverter(PvaConverter):
257
- def reading(self, value):
279
+ def reading(self, value) -> Reading:
258
280
  ts = time.time()
259
281
  value = value.todict()
260
282
  # Alarm severity is vacuously 0 for a table
@@ -266,13 +288,13 @@ class PvaDictConverter(PvaConverter):
266
288
  def get_datakey(self, source: str, value) -> DataKey:
267
289
  raise NotImplementedError("Describing Dict signals not currently supported")
268
290
 
269
- def metadata_fields(self) -> List[str]:
291
+ def metadata_fields(self) -> list[str]:
270
292
  """
271
293
  Fields to request from PVA for metadata.
272
294
  """
273
295
  return []
274
296
 
275
- def value_fields(self) -> List[str]:
297
+ def value_fields(self) -> list[str]:
276
298
  """
277
299
  Fields to request from PVA for the value.
278
300
  """
@@ -284,7 +306,7 @@ class DisconnectedPvaConverter(PvaConverter):
284
306
  raise NotImplementedError("No PV has been set as connect() has not been called")
285
307
 
286
308
 
287
- def make_converter(datatype: Optional[Type], values: Dict[str, Any]) -> PvaConverter:
309
+ def make_converter(datatype: type | None, values: dict[str, Any]) -> PvaConverter:
288
310
  pv = list(values)[0]
289
311
  typeid = get_unique({k: v.getID() for k, v in values.items()}, "typeids")
290
312
  typ = get_unique(
@@ -333,7 +355,7 @@ def make_converter(datatype: Optional[Type], values: Dict[str, Any]) -> PvaConve
333
355
  and issubclass(datatype, RuntimeSubsetEnum)
334
356
  ):
335
357
  return PvaEnumConverter(
336
- get_supported_values(pv, datatype, datatype.choices)
358
+ get_supported_values(pv, datatype, datatype.choices) # type: ignore
337
359
  )
338
360
  elif datatype and not issubclass(typ, datatype):
339
361
  # Allow int signals to represent float records when prec is 0
@@ -348,6 +370,8 @@ def make_converter(datatype: Optional[Type], values: Dict[str, Any]) -> PvaConve
348
370
  raise TypeError(f"{pv} has type {typ.__name__} not {datatype.__name__}")
349
371
  return PvaConverter()
350
372
  elif "NTTable" in typeid:
373
+ if is_pydantic_model(datatype):
374
+ return PvaPydanticModelConverter(datatype) # type: ignore
351
375
  return PvaTableConverter()
352
376
  elif "structure" in typeid:
353
377
  return PvaDictConverter()
@@ -356,15 +380,40 @@ def make_converter(datatype: Optional[Type], values: Dict[str, Any]) -> PvaConve
356
380
 
357
381
 
358
382
  class PvaSignalBackend(SignalBackend[T]):
359
- _ctxt: Optional[Context] = None
383
+ _ctxt: Context | None = None
384
+
385
+ _ALLOWED_DATATYPES = (
386
+ bool,
387
+ int,
388
+ float,
389
+ str,
390
+ Sequence,
391
+ np.ndarray,
392
+ Enum,
393
+ RuntimeSubsetEnum,
394
+ BaseModel,
395
+ dict,
396
+ )
360
397
 
361
- def __init__(self, datatype: Optional[Type[T]], read_pv: str, write_pv: str):
398
+ @classmethod
399
+ def datatype_allowed(cls, dtype: Any) -> bool:
400
+ stripped_origin = get_origin(dtype) or dtype
401
+ if dtype is None:
402
+ return True
403
+ return inspect.isclass(stripped_origin) and issubclass(
404
+ stripped_origin, cls._ALLOWED_DATATYPES
405
+ )
406
+
407
+ def __init__(self, datatype: type[T] | None, read_pv: str, write_pv: str):
362
408
  self.datatype = datatype
409
+ if not PvaSignalBackend.datatype_allowed(self.datatype):
410
+ raise TypeError(f"Given datatype {self.datatype} unsupported in PVA.")
411
+
363
412
  self.read_pv = read_pv
364
413
  self.write_pv = write_pv
365
- self.initial_values: Dict[str, Any] = {}
414
+ self.initial_values: dict[str, Any] = {}
366
415
  self.converter: PvaConverter = DisconnectedPvaConverter()
367
- self.subscription: Optional[Subscription] = None
416
+ self.subscription: Subscription | None = None
368
417
 
369
418
  def source(self, name: str):
370
419
  return f"pva://{self.read_pv}"
@@ -404,7 +453,7 @@ class PvaSignalBackend(SignalBackend[T]):
404
453
  await self._store_initial_value(self.read_pv, timeout=timeout)
405
454
  self.converter = make_converter(self.datatype, self.initial_values)
406
455
 
407
- async def put(self, value: Optional[T], wait=True, timeout=None):
456
+ async def put(self, value: T | None, wait=True, timeout=None):
408
457
  if value is None:
409
458
  write_value = self.initial_values[self.write_pv]
410
459
  else:
@@ -424,7 +473,7 @@ class PvaSignalBackend(SignalBackend[T]):
424
473
  value = await self.ctxt.get(self.read_pv)
425
474
  return self.converter.get_datakey(source, value)
426
475
 
427
- def _pva_request_string(self, fields: List[str]) -> str:
476
+ def _pva_request_string(self, fields: list[str]) -> str:
428
477
  """
429
478
  Converts a list of requested fields into a PVA request string which can be
430
479
  passed to p4p.
@@ -447,7 +496,7 @@ class PvaSignalBackend(SignalBackend[T]):
447
496
  value = await self.ctxt.get(self.write_pv, "field(value)")
448
497
  return self.converter.value(value)
449
498
 
450
- def set_callback(self, callback: Optional[ReadingValueCallback[T]]) -> None:
499
+ def set_callback(self, callback: ReadingValueCallback[T] | None) -> None:
451
500
  if callback:
452
501
  assert (
453
502
  not self.subscription
@@ -2,8 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Optional, Tuple, Type
6
-
7
5
  from ophyd_async.core import (
8
6
  SignalBackend,
9
7
  SignalR,
@@ -19,7 +17,7 @@ from ._epics_transport import _EpicsTransport
19
17
  _default_epics_transport = _EpicsTransport.ca
20
18
 
21
19
 
22
- def _transport_pv(pv: str) -> Tuple[_EpicsTransport, str]:
20
+ def _transport_pv(pv: str) -> tuple[_EpicsTransport, str]:
23
21
  split = pv.split("://", 1)
24
22
  if len(split) > 1:
25
23
  # We got something like pva://mydevice, so use specified comms mode
@@ -32,7 +30,7 @@ def _transport_pv(pv: str) -> Tuple[_EpicsTransport, str]:
32
30
 
33
31
 
34
32
  def _epics_signal_backend(
35
- datatype: Optional[Type[T]], read_pv: str, write_pv: str
33
+ datatype: type[T] | None, read_pv: str, write_pv: str
36
34
  ) -> SignalBackend[T]:
37
35
  """Create an epics signal backend."""
38
36
  r_transport, r_pv = _transport_pv(read_pv)
@@ -42,7 +40,7 @@ def _epics_signal_backend(
42
40
 
43
41
 
44
42
  def epics_signal_rw(
45
- datatype: Type[T], read_pv: str, write_pv: Optional[str] = None, name: str = ""
43
+ datatype: type[T], read_pv: str, write_pv: str | None = None, name: str = ""
46
44
  ) -> SignalRW[T]:
47
45
  """Create a `SignalRW` backed by 1 or 2 EPICS PVs
48
46
 
@@ -60,7 +58,7 @@ def epics_signal_rw(
60
58
 
61
59
 
62
60
  def epics_signal_rw_rbv(
63
- datatype: Type[T], write_pv: str, read_suffix: str = "_RBV", name: str = ""
61
+ datatype: type[T], write_pv: str, read_suffix: str = "_RBV", name: str = ""
64
62
  ) -> SignalRW[T]:
65
63
  """Create a `SignalRW` backed by 1 or 2 EPICS PVs, with a suffix on the readback pv
66
64
 
@@ -76,7 +74,7 @@ def epics_signal_rw_rbv(
76
74
  return epics_signal_rw(datatype, f"{write_pv}{read_suffix}", write_pv, name)
77
75
 
78
76
 
79
- def epics_signal_r(datatype: Type[T], read_pv: str, name: str = "") -> SignalR[T]:
77
+ def epics_signal_r(datatype: type[T], read_pv: str, name: str = "") -> SignalR[T]:
80
78
  """Create a `SignalR` backed by 1 EPICS PV
81
79
 
82
80
  Parameters
@@ -90,7 +88,7 @@ def epics_signal_r(datatype: Type[T], read_pv: str, name: str = "") -> SignalR[T
90
88
  return SignalR(backend, name=name)
91
89
 
92
90
 
93
- def epics_signal_w(datatype: Type[T], write_pv: str, name: str = "") -> SignalW[T]:
91
+ def epics_signal_w(datatype: type[T], write_pv: str, name: str = "") -> SignalW[T]:
94
92
  """Create a `SignalW` backed by 1 EPICS PVs
95
93
 
96
94
  Parameters
@@ -15,10 +15,7 @@ from ._table import (
15
15
  DatasetTable,
16
16
  PandaHdf5DatasetType,
17
17
  SeqTable,
18
- SeqTableRow,
19
18
  SeqTrigger,
20
- seq_table_from_arrays,
21
- seq_table_from_rows,
22
19
  )
23
20
  from ._trigger import (
24
21
  PcompInfo,
@@ -45,10 +42,7 @@ __all__ = [
45
42
  "DatasetTable",
46
43
  "PandaHdf5DatasetType",
47
44
  "SeqTable",
48
- "SeqTableRow",
49
45
  "SeqTrigger",
50
- "seq_table_from_arrays",
51
- "seq_table_from_rows",
52
46
  "PcompInfo",
53
47
  "SeqTableInfo",
54
48
  "StaticPcompTriggerLogic",
@@ -1,12 +1,12 @@
1
1
  import asyncio
2
- from typing import Optional
3
2
 
4
3
  from ophyd_async.core import (
5
- AsyncStatus,
6
4
  DetectorControl,
7
5
  DetectorTrigger,
8
6
  wait_for_value,
9
7
  )
8
+ from ophyd_async.core._detector import TriggerInfo
9
+ from ophyd_async.core._status import AsyncStatus
10
10
 
11
11
  from ._block import PcapBlock
12
12
 
@@ -14,25 +14,24 @@ from ._block import PcapBlock
14
14
  class PandaPcapController(DetectorControl):
15
15
  def __init__(self, pcap: PcapBlock) -> None:
16
16
  self.pcap = pcap
17
+ self._arm_status: AsyncStatus | None = None
17
18
 
18
- def get_deadtime(self, exposure: float) -> float:
19
+ def get_deadtime(self, exposure: float | None) -> float:
19
20
  return 0.000000008
20
21
 
21
- async def arm(
22
- self,
23
- num: int,
24
- trigger: DetectorTrigger = DetectorTrigger.constant_gate,
25
- exposure: Optional[float] = None,
26
- ) -> AsyncStatus:
27
- assert trigger in (
22
+ async def prepare(self, trigger_info: TriggerInfo):
23
+ assert trigger_info.trigger in (
28
24
  DetectorTrigger.constant_gate,
29
- trigger == DetectorTrigger.variable_gate,
25
+ DetectorTrigger.variable_gate,
30
26
  ), "Only constant_gate and variable_gate triggering is supported on the PandA"
31
- await asyncio.gather(self.pcap.arm.set(True))
27
+
28
+ async def arm(self):
29
+ self._arm_status = self.pcap.arm.set(True)
32
30
  await wait_for_value(self.pcap.active, True, timeout=1)
33
- return AsyncStatus(wait_for_value(self.pcap.active, False, timeout=None))
34
31
 
35
- async def disarm(self) -> AsyncStatus:
32
+ async def wait_for_idle(self):
33
+ pass
34
+
35
+ async def disarm(self):
36
36
  await asyncio.gather(self.pcap.arm.set(False))
37
37
  await wait_for_value(self.pcap.active, False, timeout=1)
38
- return AsyncStatus(wait_for_value(self.pcap.active, False, timeout=None))
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Sequence
3
+ from collections.abc import Sequence
4
4
 
5
5
  from ophyd_async.core import DEFAULT_TIMEOUT, PathProvider, SignalR, StandardDetector
6
6
  from ophyd_async.epics.pvi import create_children_from_annotations, fill_pvi_entries
@@ -36,7 +36,14 @@ class HDFPanda(CommonPandaBlocks, StandardDetector):
36
36
  )
37
37
 
38
38
  async def connect(
39
- self, mock: bool = False, timeout: float = DEFAULT_TIMEOUT
40
- ) -> None:
39
+ self,
40
+ mock: bool = False,
41
+ timeout: float = DEFAULT_TIMEOUT,
42
+ force_reconnect: bool = False,
43
+ ):
44
+ # TODO: this doesn't support caching
45
+ # https://github.com/bluesky/ophyd-async/issues/472
41
46
  await fill_pvi_entries(self, self._prefix + "PVI", timeout=timeout, mock=mock)
42
- await super().connect(mock=mock, timeout=timeout)
47
+ await super().connect(
48
+ mock=mock, timeout=timeout, force_reconnect=force_reconnect
49
+ )