ophyd-async 0.3a3__py3-none-any.whl → 0.3a4__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 (31) hide show
  1. ophyd_async/_version.py +1 -1
  2. ophyd_async/core/__init__.py +24 -10
  3. ophyd_async/core/async_status.py +2 -0
  4. ophyd_async/core/device.py +22 -9
  5. ophyd_async/core/mock_signal_backend.py +86 -0
  6. ophyd_async/core/mock_signal_utils.py +149 -0
  7. ophyd_async/core/signal.py +38 -42
  8. ophyd_async/core/{sim_signal_backend.py → soft_signal_backend.py} +23 -33
  9. ophyd_async/epics/_backend/_aioca.py +11 -7
  10. ophyd_async/epics/_backend/_p4p.py +11 -7
  11. ophyd_async/epics/_backend/common.py +17 -17
  12. ophyd_async/epics/areadetector/__init__.py +0 -4
  13. ophyd_async/epics/areadetector/drivers/ad_base.py +12 -10
  14. ophyd_async/epics/areadetector/drivers/aravis_driver.py +7 -5
  15. ophyd_async/epics/areadetector/drivers/kinetix_driver.py +7 -4
  16. ophyd_async/epics/areadetector/drivers/pilatus_driver.py +5 -2
  17. ophyd_async/epics/areadetector/drivers/vimba_driver.py +12 -7
  18. ophyd_async/epics/areadetector/utils.py +2 -12
  19. ophyd_async/epics/areadetector/writers/nd_file_hdf.py +21 -19
  20. ophyd_async/epics/areadetector/writers/nd_plugin.py +6 -7
  21. ophyd_async/epics/motion/motor.py +5 -1
  22. ophyd_async/epics/pvi/pvi.py +11 -11
  23. ophyd_async/panda/_hdf_panda.py +3 -3
  24. ophyd_async/sim/demo/sim_motor.py +4 -4
  25. ophyd_async/sim/pattern_generator.py +5 -5
  26. {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a4.dist-info}/METADATA +2 -2
  27. {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a4.dist-info}/RECORD +31 -29
  28. {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a4.dist-info}/LICENSE +0 -0
  29. {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a4.dist-info}/WHEEL +0 -0
  30. {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a4.dist-info}/entry_points.txt +0 -0
  31. {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a4.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
- import asyncio
4
3
  import inspect
5
4
  import time
6
5
  from collections import abc
7
6
  from dataclasses import dataclass
8
7
  from enum import Enum
9
- from typing import Any, Dict, Generic, Optional, Type, Union, cast, get_origin
8
+ from typing import Dict, Generic, Optional, Type, Union, cast, get_origin
10
9
 
11
10
  import numpy as np
12
11
  from bluesky.protocols import DataKey, Dtype, Reading
@@ -22,7 +21,7 @@ primitive_dtypes: Dict[type, Dtype] = {
22
21
  }
23
22
 
24
23
 
25
- class SimConverter(Generic[T]):
24
+ class SoftConverter(Generic[T]):
26
25
  def value(self, value: T) -> T:
27
26
  return value
28
27
 
@@ -55,7 +54,7 @@ class SimConverter(Generic[T]):
55
54
  return datatype()
56
55
 
57
56
 
58
- class SimArrayConverter(SimConverter):
57
+ class SoftArrayConverter(SoftConverter):
59
58
  def get_datakey(self, source: str, value) -> DataKey:
60
59
  return {"source": source, "dtype": "array", "shape": [len(value)]}
61
60
 
@@ -70,7 +69,7 @@ class SimArrayConverter(SimConverter):
70
69
 
71
70
 
72
71
  @dataclass
73
- class SimEnumConverter(SimConverter):
72
+ class SoftEnumConverter(SoftConverter):
74
73
  enum_class: Type[Enum]
75
74
 
76
75
  def write_value(self, value: Union[Enum, str]) -> Enum:
@@ -90,26 +89,21 @@ class SimEnumConverter(SimConverter):
90
89
  return cast(T, list(datatype.__members__.values())[0]) # type: ignore
91
90
 
92
91
 
93
- class DisconnectedSimConverter(SimConverter):
94
- def __getattribute__(self, __name: str) -> Any:
95
- raise NotImplementedError("No PV has been set as connect() has not been called")
96
-
97
-
98
92
  def make_converter(datatype):
99
93
  is_array = get_dtype(datatype) is not None
100
94
  is_sequence = get_origin(datatype) == abc.Sequence
101
95
  is_enum = issubclass(datatype, Enum) if inspect.isclass(datatype) else False
102
96
 
103
97
  if is_array or is_sequence:
104
- return SimArrayConverter()
98
+ return SoftArrayConverter()
105
99
  if is_enum:
106
- return SimEnumConverter(datatype)
100
+ return SoftEnumConverter(datatype)
107
101
 
108
- return SimConverter()
102
+ return SoftConverter()
109
103
 
110
104
 
111
- class SimSignalBackend(SignalBackend[T]):
112
- """An simulated backend to a Signal, created with ``Signal.connect(sim=True)``"""
105
+ class SoftSignalBackend(SignalBackend[T]):
106
+ """An backend to a soft Signal, for test signals see ``MockSignalBackend``."""
113
107
 
114
108
  _value: T
115
109
  _initial_value: Optional[T]
@@ -122,25 +116,23 @@ class SimSignalBackend(SignalBackend[T]):
122
116
  initial_value: Optional[T] = None,
123
117
  ) -> None:
124
118
  self.datatype = datatype
125
- self.converter: SimConverter = DisconnectedSimConverter()
126
119
  self._initial_value = initial_value
127
- self.put_proceeds = asyncio.Event()
128
- self.put_proceeds.set()
129
- self.callback: Optional[ReadingValueCallback[T]] = None
130
-
131
- def source(self, name: str) -> str:
132
- return f"soft://{name}"
133
-
134
- async def connect(self, timeout: float = DEFAULT_TIMEOUT) -> None:
135
- self.converter = make_converter(self.datatype)
120
+ self.converter: SoftConverter = make_converter(datatype)
136
121
  if self._initial_value is None:
137
122
  self._initial_value = self.converter.make_initial_value(self.datatype)
138
123
  else:
139
- # convert potentially unconverted initial value passed to init method
140
124
  self._initial_value = self.converter.write_value(self._initial_value)
125
+
126
+ self.callback: Optional[ReadingValueCallback[T]] = None
141
127
  self._severity = 0
128
+ self.set_value(self._initial_value)
142
129
 
143
- await self.put(None)
130
+ def source(self, name: str) -> str:
131
+ return f"soft://{name}"
132
+
133
+ async def connect(self, timeout: float = DEFAULT_TIMEOUT) -> None:
134
+ """Connection isn't required for soft signals."""
135
+ pass
144
136
 
145
137
  async def put(self, value: Optional[T], wait=True, timeout=None):
146
138
  write_value = (
@@ -148,13 +140,11 @@ class SimSignalBackend(SignalBackend[T]):
148
140
  if value is not None
149
141
  else self._initial_value
150
142
  )
151
- self._set_value(write_value)
152
143
 
153
- if wait:
154
- await asyncio.wait_for(self.put_proceeds.wait(), timeout)
144
+ self.set_value(write_value)
155
145
 
156
- def _set_value(self, value: T):
157
- """Method to bypass asynchronous logic, designed to only be used in tests."""
146
+ def set_value(self, value: T):
147
+ """Method to bypass asynchronous logic."""
158
148
  self._value = value
159
149
  self._timestamp = time.monotonic()
160
150
  reading: Reading = self.converter.reading(
@@ -174,7 +164,7 @@ class SimSignalBackend(SignalBackend[T]):
174
164
  return self.converter.value(self._value)
175
165
 
176
166
  async def get_setpoint(self) -> T:
177
- """For a simulated backend, the setpoint and readback values are the same."""
167
+ """For a soft signal, the setpoint and readback values are the same."""
178
168
  return await self.get_value()
179
169
 
180
170
  def set_callback(self, callback: Optional[ReadingValueCallback[T]]) -> None:
@@ -28,7 +28,7 @@ from ophyd_async.core import (
28
28
  )
29
29
  from ophyd_async.core.utils import DEFAULT_TIMEOUT, NotConnected
30
30
 
31
- from .common import get_supported_enum_class
31
+ from .common import get_supported_values
32
32
 
33
33
  dbr_to_dtype: Dict[Dbr, Dtype] = {
34
34
  dbr.DBR_STRING: "string",
@@ -79,7 +79,7 @@ class CaArrayConverter(CaConverter):
79
79
 
80
80
  @dataclass
81
81
  class CaEnumConverter(CaConverter):
82
- enum_class: Type[Enum]
82
+ choices: dict[str, str]
83
83
 
84
84
  def write_value(self, value: Union[Enum, str]):
85
85
  if isinstance(value, Enum):
@@ -88,11 +88,15 @@ class CaEnumConverter(CaConverter):
88
88
  return value
89
89
 
90
90
  def value(self, value: AugmentedValue):
91
- return self.enum_class(value)
91
+ return self.choices[value]
92
92
 
93
93
  def get_datakey(self, source: str, value: AugmentedValue) -> DataKey:
94
- choices = [e.value for e in self.enum_class]
95
- return {"source": source, "dtype": "string", "shape": [], "choices": choices}
94
+ return {
95
+ "source": source,
96
+ "dtype": "string",
97
+ "shape": [],
98
+ "choices": list(self.choices),
99
+ }
96
100
 
97
101
 
98
102
  class DisconnectedCaConverter(CaConverter):
@@ -138,8 +142,8 @@ def make_converter(
138
142
  pv_choices = get_unique(
139
143
  {k: tuple(v.enums) for k, v in values.items()}, "choices"
140
144
  )
141
- enum_class = get_supported_enum_class(pv, datatype, pv_choices)
142
- return CaEnumConverter(dbr.DBR_STRING, None, enum_class)
145
+ supported_values = get_supported_values(pv, datatype, pv_choices)
146
+ return CaEnumConverter(dbr.DBR_STRING, None, supported_values)
143
147
  else:
144
148
  value = list(values.values())[0]
145
149
  # Done the dbr check, so enough to check one of the values
@@ -20,7 +20,7 @@ from ophyd_async.core import (
20
20
  )
21
21
  from ophyd_async.core.utils import DEFAULT_TIMEOUT, NotConnected
22
22
 
23
- from .common import get_supported_enum_class
23
+ from .common import get_supported_values
24
24
 
25
25
  # https://mdavidsaver.github.io/p4p/values.html
26
26
  specifier_to_dtype: Dict[str, Dtype] = {
@@ -109,7 +109,8 @@ class PvaNDArrayConverter(PvaConverter):
109
109
 
110
110
  @dataclass
111
111
  class PvaEnumConverter(PvaConverter):
112
- enum_class: Type[Enum]
112
+ def __init__(self, choices: dict[str, str]):
113
+ self.choices = tuple(choices.values())
113
114
 
114
115
  def write_value(self, value: Union[Enum, str]):
115
116
  if isinstance(value, Enum):
@@ -118,11 +119,15 @@ class PvaEnumConverter(PvaConverter):
118
119
  return value
119
120
 
120
121
  def value(self, value):
121
- return list(self.enum_class)[value["value"]["index"]]
122
+ return self.choices[value["value"]["index"]]
122
123
 
123
124
  def get_datakey(self, source: str, value) -> DataKey:
124
- choices = [e.value for e in self.enum_class]
125
- return {"source": source, "dtype": "string", "shape": [], "choices": choices}
125
+ return {
126
+ "source": source,
127
+ "dtype": "string",
128
+ "shape": [],
129
+ "choices": list(self.choices),
130
+ }
126
131
 
127
132
 
128
133
  class PvaEnumBoolConverter(PvaConverter):
@@ -214,7 +219,7 @@ def make_converter(datatype: Optional[Type], values: Dict[str, Any]) -> PvaConve
214
219
  pv_choices = get_unique(
215
220
  {k: tuple(v["value"]["choices"]) for k, v in values.items()}, "choices"
216
221
  )
217
- return PvaEnumConverter(get_supported_enum_class(pv, datatype, pv_choices))
222
+ return PvaEnumConverter(get_supported_values(pv, datatype, pv_choices))
218
223
  elif "NTScalar" in typeid:
219
224
  if (
220
225
  datatype
@@ -244,7 +249,6 @@ class PvaSignalBackend(SignalBackend[T]):
244
249
  self.converter: PvaConverter = DisconnectedPvaConverter()
245
250
  self.subscription: Optional[Subscription] = None
246
251
 
247
- @property
248
252
  def source(self, name: str):
249
253
  return f"pva://{self.read_pv}"
250
254
 
@@ -1,25 +1,25 @@
1
1
  from enum import Enum
2
- from typing import Any, Optional, Tuple, Type
2
+ from typing import Dict, Optional, Tuple, Type
3
3
 
4
4
 
5
- def get_supported_enum_class(
5
+ def get_supported_values(
6
6
  pv: str,
7
- datatype: Optional[Type[Enum]],
8
- pv_choices: Tuple[Any, ...],
9
- ) -> Type[Enum]:
7
+ datatype: Optional[Type[str]],
8
+ pv_choices: Tuple[str, ...],
9
+ ) -> Dict[str, str]:
10
10
  if not datatype:
11
- return Enum("GeneratedChoices", {x or "_": x for x in pv_choices}, type=str) # type: ignore
11
+ return {x: x or "_" for x in pv_choices}
12
12
 
13
- if not issubclass(datatype, Enum):
14
- raise TypeError(f"{pv} has type Enum not {datatype.__name__}")
15
13
  if not issubclass(datatype, str):
16
- raise TypeError(f"{pv} has type Enum but doesn't inherit from String")
17
- choices = tuple(v.value for v in datatype)
18
- if set(choices) != set(pv_choices):
19
- raise TypeError(
20
- (
21
- f"{pv} has choices {pv_choices}, "
22
- f"which do not match {datatype}, which has {choices}"
14
+ raise TypeError(f"{pv} is type Enum but doesn't inherit from String")
15
+ if issubclass(datatype, Enum):
16
+ choices = tuple(v.value for v in datatype)
17
+ if set(choices) != set(pv_choices):
18
+ raise TypeError(
19
+ (
20
+ f"{pv} has choices {pv_choices}, "
21
+ f"which do not match {datatype}, which has {choices}"
22
+ )
23
23
  )
24
- )
25
- return datatype
24
+ return {x: datatype(x) for x in pv_choices}
25
+ return {x: x for x in pv_choices}
@@ -7,8 +7,6 @@ from .utils import (
7
7
  ImageMode,
8
8
  NDAttributeDataType,
9
9
  NDAttributesXML,
10
- ad_r,
11
- ad_rw,
12
10
  )
13
11
  from .vimba import VimbaDetector
14
12
 
@@ -19,8 +17,6 @@ __all__ = [
19
17
  "SingleTriggerDet",
20
18
  "FileWriteMode",
21
19
  "ImageMode",
22
- "ad_r",
23
- "ad_rw",
24
20
  "NDAttributeDataType",
25
21
  "NDAttributesXML",
26
22
  "PilatusDetector",
@@ -9,8 +9,8 @@ from ophyd_async.core import (
9
9
  set_and_wait_for_value,
10
10
  )
11
11
 
12
- from ...signal.signal import epics_signal_rw
13
- from ..utils import ImageMode, ad_r, ad_rw
12
+ from ...signal.signal import epics_signal_r, epics_signal_rw, epics_signal_rw_rbv
13
+ from ..utils import ImageMode
14
14
  from ..writers.nd_plugin import NDArrayBase
15
15
 
16
16
 
@@ -43,14 +43,16 @@ DEFAULT_GOOD_STATES: FrozenSet[DetectorState] = frozenset(
43
43
  class ADBase(NDArrayBase):
44
44
  def __init__(self, prefix: str, name: str = "") -> None:
45
45
  # Define some signals
46
- self.acquire = ad_rw(bool, prefix + "Acquire")
47
- self.acquire_time = ad_rw(float, prefix + "AcquireTime")
48
- self.num_images = ad_rw(int, prefix + "NumImages")
49
- self.image_mode = ad_rw(ImageMode, prefix + "ImageMode")
50
- self.array_counter = ad_rw(int, prefix + "ArrayCounter")
51
- self.array_size_x = ad_r(int, prefix + "ArraySizeX")
52
- self.array_size_y = ad_r(int, prefix + "ArraySizeY")
53
- self.detector_state = ad_r(DetectorState, prefix + "DetectorState")
46
+ self.acquire = epics_signal_rw_rbv(bool, prefix + "Acquire")
47
+ self.acquire_time = epics_signal_rw_rbv(float, prefix + "AcquireTime")
48
+ self.num_images = epics_signal_rw_rbv(int, prefix + "NumImages")
49
+ self.image_mode = epics_signal_rw_rbv(ImageMode, prefix + "ImageMode")
50
+ self.array_counter = epics_signal_rw_rbv(int, prefix + "ArrayCounter")
51
+ self.array_size_x = epics_signal_r(int, prefix + "ArraySizeX_RBV")
52
+ self.array_size_y = epics_signal_r(int, prefix + "ArraySizeY_RBV")
53
+ self.detector_state = epics_signal_r(
54
+ DetectorState, prefix + "DetectorState_RBV"
55
+ )
54
56
  # There is no _RBV for this one
55
57
  self.wait_for_plugins = epics_signal_rw(bool, prefix + "WaitForPlugins")
56
58
  super().__init__(prefix, name=name)
@@ -2,7 +2,7 @@ from enum import Enum
2
2
  from typing import Callable, Dict, Literal, Optional, Tuple
3
3
 
4
4
  from ophyd_async.epics.areadetector.drivers import ADBase
5
- from ophyd_async.epics.areadetector.utils import ad_r, ad_rw
5
+ from ophyd_async.epics.signal.signal import epics_signal_r, epics_signal_rw_rbv
6
6
 
7
7
 
8
8
  class AravisTriggerMode(str, Enum):
@@ -138,10 +138,12 @@ class AravisDriver(ADBase):
138
138
  """
139
139
 
140
140
  def __init__(self, prefix: str, name: str = "") -> None:
141
- self.trigger_mode = ad_rw(AravisTriggerMode, prefix + "TriggerMode")
142
- self.trigger_source = ad_rw(str, prefix + "TriggerSource")
143
- self.model = ad_r(str, prefix + "Model")
144
- self.pixel_format = ad_rw(str, prefix + "PixelFormat")
141
+ self.trigger_mode = epics_signal_rw_rbv(
142
+ AravisTriggerMode, prefix + "TriggerMode"
143
+ )
144
+ self.trigger_source = epics_signal_rw_rbv(str, prefix + "TriggerSource")
145
+ self.model = epics_signal_r(str, prefix + "Model_RBV")
146
+ self.pixel_format = epics_signal_rw_rbv(str, prefix + "PixelFormat")
145
147
  self.dead_time: Optional[float] = None
146
148
  super().__init__(prefix, name=name)
147
149
 
@@ -1,6 +1,7 @@
1
1
  from enum import Enum
2
2
 
3
- from ..utils import ad_rw
3
+ from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
4
+
4
5
  from .ad_base import ADBase
5
6
 
6
7
 
@@ -18,7 +19,9 @@ class KinetixReadoutMode(str, Enum):
18
19
 
19
20
  class KinetixDriver(ADBase):
20
21
  def __init__(self, prefix: str, name: str = "") -> None:
21
- # self.pixel_format = ad_rw(PixelFormat, prefix + "PixelFormat")
22
- self.trigger_mode = ad_rw(KinetixTriggerMode, prefix + "TriggerMode")
23
- self.mode = ad_rw(KinetixReadoutMode, prefix + "ReadoutPortIdx")
22
+ # self.pixel_format = epics_signal_rw_rbv(PixelFormat, prefix + "PixelFormat")
23
+ self.trigger_mode = epics_signal_rw_rbv(
24
+ KinetixTriggerMode, prefix + "TriggerMode"
25
+ )
26
+ self.mode = epics_signal_rw_rbv(KinetixReadoutMode, prefix + "ReadoutPortIdx")
24
27
  super().__init__(prefix, name)
@@ -1,6 +1,7 @@
1
1
  from enum import Enum
2
2
 
3
- from ..utils import ad_rw
3
+ from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
4
+
4
5
  from .ad_base import ADBase
5
6
 
6
7
 
@@ -14,5 +15,7 @@ class PilatusTriggerMode(str, Enum):
14
15
 
15
16
  class PilatusDriver(ADBase):
16
17
  def __init__(self, prefix: str, name: str = "") -> None:
17
- self.trigger_mode = ad_rw(PilatusTriggerMode, prefix + "TriggerMode")
18
+ self.trigger_mode = epics_signal_rw_rbv(
19
+ PilatusTriggerMode, prefix + "TriggerMode"
20
+ )
18
21
  super().__init__(prefix, name)
@@ -1,6 +1,7 @@
1
1
  from enum import Enum
2
2
 
3
- from ..utils import ad_rw
3
+ from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
4
+
4
5
  from .ad_base import ADBase
5
6
 
6
7
 
@@ -47,12 +48,16 @@ class VimbaExposeOutMode(str, Enum):
47
48
 
48
49
  class VimbaDriver(ADBase):
49
50
  def __init__(self, prefix: str, name: str = "") -> None:
50
- # self.pixel_format = ad_rw(PixelFormat, prefix + "PixelFormat")
51
- self.convert_format = ad_rw(
51
+ # self.pixel_format = epics_signal_rw_rbv(PixelFormat, prefix + "PixelFormat")
52
+ self.convert_format = epics_signal_rw_rbv(
52
53
  VimbaConvertFormat, prefix + "ConvertPixelFormat"
53
54
  ) # Pixel format of data outputted to AD
54
- self.trig_source = ad_rw(VimbaTriggerSource, prefix + "TriggerSource")
55
- self.trigger_mode = ad_rw(VimbaOnOff, prefix + "TriggerMode")
56
- self.overlap = ad_rw(VimbaOverlap, prefix + "TriggerOverlap")
57
- self.expose_mode = ad_rw(VimbaExposeOutMode, prefix + "ExposureMode")
55
+ self.trig_source = epics_signal_rw_rbv(
56
+ VimbaTriggerSource, prefix + "TriggerSource"
57
+ )
58
+ self.trigger_mode = epics_signal_rw_rbv(VimbaOnOff, prefix + "TriggerMode")
59
+ self.overlap = epics_signal_rw_rbv(VimbaOverlap, prefix + "TriggerOverlap")
60
+ self.expose_mode = epics_signal_rw_rbv(
61
+ VimbaExposeOutMode, prefix + "ExposureMode"
62
+ )
58
63
  super().__init__(prefix, name)
@@ -1,18 +1,8 @@
1
1
  from enum import Enum
2
- from typing import Optional, Type
2
+ from typing import Optional
3
3
  from xml.etree import cElementTree as ET
4
4
 
5
- from ophyd_async.core import DEFAULT_TIMEOUT, SignalR, SignalRW, T, wait_for_value
6
-
7
- from ..signal.signal import epics_signal_r, epics_signal_rw
8
-
9
-
10
- def ad_rw(datatype: Type[T], prefix: str) -> SignalRW[T]:
11
- return epics_signal_rw(datatype, prefix + "_RBV", prefix)
12
-
13
-
14
- def ad_r(datatype: Type[T], prefix: str) -> SignalR[T]:
15
- return epics_signal_r(datatype, prefix + "_RBV")
5
+ from ophyd_async.core import DEFAULT_TIMEOUT, SignalRW, T, wait_for_value
16
6
 
17
7
 
18
8
  class FileWriteMode(str, Enum):
@@ -1,7 +1,7 @@
1
1
  from enum import Enum
2
2
 
3
- from ...signal.signal import epics_signal_rw
4
- from ..utils import FileWriteMode, ad_r, ad_rw
3
+ from ...signal.signal import epics_signal_r, epics_signal_rw, epics_signal_rw_rbv
4
+ from ..utils import FileWriteMode
5
5
  from .nd_plugin import NDPluginBase
6
6
 
7
7
 
@@ -19,22 +19,24 @@ class Compression(str, Enum):
19
19
  class NDFileHDF(NDPluginBase):
20
20
  def __init__(self, prefix: str, name="") -> None:
21
21
  # Define some signals
22
- self.position_mode = ad_rw(bool, prefix + "PositionMode")
23
- self.compression = ad_rw(Compression, prefix + "Compression")
24
- self.num_extra_dims = ad_rw(int, prefix + "NumExtraDims")
25
- self.file_path = ad_rw(str, prefix + "FilePath")
26
- self.file_name = ad_rw(str, prefix + "FileName")
27
- self.file_path_exists = ad_r(bool, prefix + "FilePathExists")
28
- self.file_template = ad_rw(str, prefix + "FileTemplate")
29
- self.full_file_name = ad_r(str, prefix + "FullFileName")
30
- self.file_write_mode = ad_rw(FileWriteMode, prefix + "FileWriteMode")
31
- self.num_capture = ad_rw(int, prefix + "NumCapture")
32
- self.num_captured = ad_r(int, prefix + "NumCaptured")
33
- self.swmr_mode = ad_rw(bool, prefix + "SWMRMode")
34
- self.lazy_open = ad_rw(bool, prefix + "LazyOpen")
35
- self.capture = ad_rw(bool, prefix + "Capture")
22
+ self.position_mode = epics_signal_rw_rbv(bool, prefix + "PositionMode")
23
+ self.compression = epics_signal_rw_rbv(Compression, prefix + "Compression")
24
+ self.num_extra_dims = epics_signal_rw_rbv(int, prefix + "NumExtraDims")
25
+ self.file_path = epics_signal_rw_rbv(str, prefix + "FilePath")
26
+ self.file_name = epics_signal_rw_rbv(str, prefix + "FileName")
27
+ self.file_path_exists = epics_signal_r(bool, prefix + "FilePathExists_RBV")
28
+ self.file_template = epics_signal_rw_rbv(str, prefix + "FileTemplate")
29
+ self.full_file_name = epics_signal_r(str, prefix + "FullFileName_RBV")
30
+ self.file_write_mode = epics_signal_rw_rbv(
31
+ FileWriteMode, prefix + "FileWriteMode"
32
+ )
33
+ self.num_capture = epics_signal_rw_rbv(int, prefix + "NumCapture")
34
+ self.num_captured = epics_signal_r(int, prefix + "NumCaptured_RBV")
35
+ self.swmr_mode = epics_signal_rw_rbv(bool, prefix + "SWMRMode")
36
+ self.lazy_open = epics_signal_rw_rbv(bool, prefix + "LazyOpen")
37
+ self.capture = epics_signal_rw_rbv(bool, prefix + "Capture")
36
38
  self.flush_now = epics_signal_rw(bool, prefix + "FlushNow")
37
- self.array_size0 = ad_r(int, prefix + "ArraySize0")
38
- self.array_size1 = ad_r(int, prefix + "ArraySize1")
39
- self.xml_file_name = ad_rw(str, prefix + "XMLFileName")
39
+ self.array_size0 = epics_signal_r(int, prefix + "ArraySize0_RBV")
40
+ self.array_size1 = epics_signal_r(int, prefix + "ArraySize1_RBV")
41
+ self.xml_file_name = epics_signal_rw_rbv(str, prefix + "XMLFileName")
40
42
  super().__init__(prefix, name)
@@ -2,8 +2,7 @@ from enum import Enum
2
2
 
3
3
  from ophyd_async.core import Device
4
4
  from ophyd_async.epics.signal import epics_signal_rw
5
-
6
- from ..utils import ad_r, ad_rw
5
+ from ophyd_async.epics.signal.signal import epics_signal_r, epics_signal_rw_rbv
7
6
 
8
7
 
9
8
  class Callback(str, Enum):
@@ -13,16 +12,16 @@ class Callback(str, Enum):
13
12
 
14
13
  class NDArrayBase(Device):
15
14
  def __init__(self, prefix: str, name: str = "") -> None:
16
- self.unique_id = ad_r(int, prefix + "UniqueId")
15
+ self.unique_id = epics_signal_r(int, prefix + "UniqueId_RBV")
17
16
  self.nd_attributes_file = epics_signal_rw(str, prefix + "NDAttributesFile")
18
- super().__init__(name)
17
+ super().__init__(name=name)
19
18
 
20
19
 
21
20
  class NDPluginBase(NDArrayBase):
22
21
  def __init__(self, prefix: str, name: str = "") -> None:
23
- self.nd_array_port = ad_rw(str, prefix + "NDArrayPort")
24
- self.enable_callback = ad_rw(Callback, prefix + "EnableCallbacks")
25
- self.nd_array_address = ad_rw(int, prefix + "NDArrayAddress")
22
+ self.nd_array_port = epics_signal_rw_rbv(str, prefix + "NDArrayPort")
23
+ self.enable_callback = epics_signal_rw_rbv(Callback, prefix + "EnableCallbacks")
24
+ self.nd_array_address = epics_signal_rw_rbv(int, prefix + "NDArrayAddress")
26
25
  super().__init__(prefix, name)
27
26
 
28
27
 
@@ -40,7 +40,11 @@ class Motor(StandardReadable, Movable, Stoppable):
40
40
  # Readback should be named the same as its parent in read()
41
41
  self.user_readback.set_name(name)
42
42
 
43
- async def _move(self, new_position: float, watchers: List[Callable] = []):
43
+ async def _move(
44
+ self, new_position: float, watchers: Optional[List[Callable]] = None
45
+ ):
46
+ if watchers is None:
47
+ watchers = []
44
48
  self._set_success = True
45
49
  start = time.monotonic()
46
50
  old_position, units, precision = await asyncio.gather(
@@ -17,7 +17,7 @@ from typing import (
17
17
  get_type_hints,
18
18
  )
19
19
 
20
- from ophyd_async.core import Device, DeviceVector, SimSignalBackend
20
+ from ophyd_async.core import Device, DeviceVector, SoftSignalBackend
21
21
  from ophyd_async.core.signal import Signal
22
22
  from ophyd_async.core.utils import DEFAULT_TIMEOUT
23
23
  from ophyd_async.epics._backend._p4p import PvaSignalBackend
@@ -156,7 +156,7 @@ def _parse_type(
156
156
  return is_device_vector, is_signal, signal_dtype, device_cls
157
157
 
158
158
 
159
- def _sim_common_blocks(device: Device, stripped_type: Optional[Type] = None):
159
+ def _mock_common_blocks(device: Device, stripped_type: Optional[Type] = None):
160
160
  device_t = stripped_type or type(device)
161
161
  sub_devices = (
162
162
  (field, field_type)
@@ -175,23 +175,23 @@ def _sim_common_blocks(device: Device, stripped_type: Optional[Type] = None):
175
175
 
176
176
  if is_device_vector:
177
177
  if is_signal:
178
- sub_device_1 = device_cls(SimSignalBackend(signal_dtype))
179
- sub_device_2 = device_cls(SimSignalBackend(signal_dtype))
178
+ sub_device_1 = device_cls(SoftSignalBackend(signal_dtype))
179
+ sub_device_2 = device_cls(SoftSignalBackend(signal_dtype))
180
180
  sub_device = DeviceVector({1: sub_device_1, 2: sub_device_2})
181
181
  else:
182
182
  sub_device = DeviceVector({1: device_cls(), 2: device_cls()})
183
183
 
184
184
  for sub_device_in_vector in sub_device.values():
185
- _sim_common_blocks(sub_device_in_vector, stripped_type=device_cls)
185
+ _mock_common_blocks(sub_device_in_vector, stripped_type=device_cls)
186
186
 
187
187
  for value in sub_device.values():
188
188
  value.parent = sub_device
189
189
  else:
190
190
  if is_signal:
191
- sub_device = device_cls(SimSignalBackend(signal_dtype))
191
+ sub_device = device_cls(SoftSignalBackend(signal_dtype))
192
192
  else:
193
193
  sub_device = getattr(device, device_name, device_cls())
194
- _sim_common_blocks(sub_device, stripped_type=device_cls)
194
+ _mock_common_blocks(sub_device, stripped_type=device_cls)
195
195
 
196
196
  setattr(device, device_name, sub_device)
197
197
  sub_device.parent = device
@@ -269,16 +269,16 @@ def _set_device_attributes(entry: PVIEntry):
269
269
 
270
270
 
271
271
  async def fill_pvi_entries(
272
- device: Device, root_pv: str, timeout=DEFAULT_TIMEOUT, sim=False
272
+ device: Device, root_pv: str, timeout=DEFAULT_TIMEOUT, mock=False
273
273
  ):
274
274
  """
275
275
  Fills a ``device`` with signals from a the ``root_pvi:PVI`` table.
276
276
 
277
277
  If the device names match with parent devices of ``device`` then types are used.
278
278
  """
279
- if sim:
280
- # set up sim signals for the common annotations
281
- _sim_common_blocks(device)
279
+ if mock:
280
+ # set up mock signals for the common annotations
281
+ _mock_common_blocks(device)
282
282
  else:
283
283
  # check the pvi table for devices and fill the device with them
284
284
  root_entry = PVIEntry(
@@ -42,7 +42,7 @@ class HDFPanda(CommonPandaBlocks, StandardDetector):
42
42
  )
43
43
 
44
44
  async def connect(
45
- self, sim: bool = False, timeout: float = DEFAULT_TIMEOUT
45
+ self, mock: bool = False, timeout: float = DEFAULT_TIMEOUT
46
46
  ) -> None:
47
- await fill_pvi_entries(self, self._prefix + "PVI", timeout=timeout, sim=sim)
48
- await super().connect(sim=sim, timeout=timeout)
47
+ await fill_pvi_entries(self, self._prefix + "PVI", timeout=timeout, mock=mock)
48
+ await super().connect(mock=mock, timeout=timeout)