diff --git a/src/ophyd_async/core/__init__.py b/src/ophyd_async/core/__init__.py index 103638019d..7381415b72 100644 --- a/src/ophyd_async/core/__init__.py +++ b/src/ophyd_async/core/__init__.py @@ -35,6 +35,8 @@ set_sim_callback, set_sim_put_proceeds, set_sim_value, + soft_signal_r_and_backend, + soft_signal_rw, wait_for_value, ) from .signal_backend import SignalBackend @@ -67,6 +69,8 @@ "SignalW", "SignalRW", "SignalX", + "soft_signal_r_and_backend", + "soft_signal_rw", "observe_value", "set_and_wait_for_value", "set_sim_callback", diff --git a/src/ophyd_async/core/signal.py b/src/ophyd_async/core/signal.py index 927faaf402..f206803475 100644 --- a/src/ophyd_async/core/signal.py +++ b/src/ophyd_async/core/signal.py @@ -2,7 +2,7 @@ import asyncio import functools -from typing import AsyncGenerator, Callable, Dict, Generic, Optional, Union +from typing import AsyncGenerator, Callable, Dict, Generic, Optional, Tuple, Type, Union from bluesky.protocols import ( Descriptor, @@ -60,9 +60,7 @@ def set_name(self, name: str = ""): async def connect(self, sim=False, timeout=DEFAULT_TIMEOUT): if sim: - self._backend = SimSignalBackend( - datatype=self._init_backend.datatype, source=self._init_backend.source - ) + self._backend = SimSignalBackend(datatype=self._init_backend.datatype) _sim_backends[self] = self._backend else: self._backend = self._init_backend @@ -72,7 +70,7 @@ async def connect(self, sim=False, timeout=DEFAULT_TIMEOUT): @property def source(self) -> str: """Like ca://PV_PREFIX:SIGNAL, or "" if not set""" - return self._backend.source + return self._backend.source(self.name) __lt__ = __le__ = __eq__ = __ge__ = __gt__ = __ne__ = _fail @@ -168,7 +166,7 @@ async def read(self, cached: Optional[bool] = None) -> Dict[str, Reading]: @_add_timeout async def describe(self) -> Dict[str, Descriptor]: """Return a single item dict with the descriptor in it""" - return {self.name: await self._backend.get_descriptor()} + return {self.name: await self._backend.get_descriptor(self.source)} @_add_timeout async def get_value(self, cached: Optional[bool] = None) -> T: @@ -253,6 +251,34 @@ def set_sim_callback(signal: Signal[T], callback: ReadingValueCallback[T]) -> No return _sim_backends[signal].set_callback(callback) +def soft_signal_rw( + datatype: Optional[Type[T]] = None, + initial_value: Optional[T] = None, + name: Optional[str] = None, +) -> SignalRW[T]: + """Creates a read-writable Signal with a SimSignalBackend""" + signal = SignalRW(SimSignalBackend(datatype, initial_value)) + if name is not None: + signal.set_name(name) + return signal + + +def soft_signal_r_and_backend( + datatype: Optional[Type[T]] = None, + initial_value: Optional[T] = None, + name: Optional[str] = None, +) -> Tuple[SignalR[T], SimSignalBackend]: + """Returns a tuple of a read-only Signal and its SimSignalBackend through + which the signal can be internally modified within the device. Use + soft_signal_rw if you want a device that is externally modifiable + """ + backend = SimSignalBackend(datatype, initial_value) + signal = SignalR(backend) + if name is not None: + signal.set_name(name) + return (signal, backend) + + async def observe_value(signal: SignalR[T], timeout=None) -> AsyncGenerator[T, None]: """Subscribe to the value of a signal so it can be iterated from. diff --git a/src/ophyd_async/core/signal_backend.py b/src/ophyd_async/core/signal_backend.py index 778e62c76c..95d0ca1768 100644 --- a/src/ophyd_async/core/signal_backend.py +++ b/src/ophyd_async/core/signal_backend.py @@ -13,7 +13,10 @@ class SignalBackend(Generic[T]): datatype: Optional[Type[T]] = None #: Like ca://PV_PREFIX:SIGNAL - source: str = "" + @abstractmethod + def source(name: str) -> str: + """Return source of signal. Signals may pass a name to the backend, which can be + used or discarded.""" @abstractmethod async def connect(self, timeout: float = DEFAULT_TIMEOUT): @@ -24,7 +27,7 @@ async def put(self, value: Optional[T], wait=True, timeout=None): """Put a value to the PV, if wait then wait for completion for up to timeout""" @abstractmethod - async def get_descriptor(self) -> Descriptor: + async def get_descriptor(self, source: str) -> Descriptor: """Metadata like source, dtype, shape, precision, units""" @abstractmethod diff --git a/src/ophyd_async/core/sim_signal_backend.py b/src/ophyd_async/core/sim_signal_backend.py index b0190344bb..1c3e10ce83 100644 --- a/src/ophyd_async/core/sim_signal_backend.py +++ b/src/ophyd_async/core/sim_signal_backend.py @@ -2,13 +2,13 @@ import asyncio import inspect -import re import time from collections import abc from dataclasses import dataclass from enum import Enum from typing import Any, Dict, Generic, Optional, Type, Union, cast, get_origin +import numpy as np from bluesky.protocols import Descriptor, Dtype, Reading from .signal_backend import SignalBackend @@ -37,11 +37,16 @@ def reading(self, value: T, timestamp: float, severity: int) -> Reading: ) def descriptor(self, source: str, value) -> Descriptor: + dtype = type(value) + if np.issubdtype(dtype, np.integer): + dtype = int + elif np.issubdtype(dtype, np.floating): + dtype = float assert ( - type(value) in primitive_dtypes + dtype in primitive_dtypes ), f"invalid converter for value of type {type(value)}" - dtype = primitive_dtypes[type(value)] - return {"source": source, "dtype": dtype, "shape": []} + dtype_name = primitive_dtypes[dtype] + return {"source": source, "dtype": dtype_name, "shape": []} def make_initial_value(self, datatype: Optional[Type[T]]) -> T: if datatype is None: @@ -107,23 +112,32 @@ class SimSignalBackend(SignalBackend[T]): """An simulated backend to a Signal, created with ``Signal.connect(sim=True)``""" _value: T - _initial_value: T + _initial_value: Optional[T] _timestamp: float _severity: int - def __init__(self, datatype: Optional[Type[T]], source: str) -> None: - pv = re.split(r"://", source)[-1] - self.source = f"sim://{pv}" + def __init__( + self, + datatype: Optional[Type[T]], + initial_value: Optional[T] = None, + ) -> None: self.datatype = datatype - self.pv = source self.converter: SimConverter = DisconnectedSimConverter() + self._initial_value = initial_value self.put_proceeds = asyncio.Event() self.put_proceeds.set() self.callback: Optional[ReadingValueCallback[T]] = None + def source(self, name: str) -> str: + return f"soft://{name}" + async def connect(self, timeout: float = DEFAULT_TIMEOUT) -> None: self.converter = make_converter(self.datatype) - self._initial_value = self.converter.make_initial_value(self.datatype) + if self._initial_value is None: + self._initial_value = self.converter.make_initial_value(self.datatype) + else: + # convert potentially unconverted initial value passed to init method + self._initial_value = self.converter.write_value(self._initial_value) self._severity = 0 await self.put(None) @@ -150,8 +164,8 @@ def _set_value(self, value: T): if self.callback: self.callback(reading, self._value) - async def get_descriptor(self) -> Descriptor: - return self.converter.descriptor(self.source, self._value) + async def get_descriptor(self, source: str) -> Descriptor: + return self.converter.descriptor(source, self._value) async def get_reading(self) -> Reading: return self.converter.reading(self._value, self._timestamp, self._severity) diff --git a/src/ophyd_async/epics/_backend/_aioca.py b/src/ophyd_async/epics/_backend/_aioca.py index db8180641b..f39a09d337 100644 --- a/src/ophyd_async/epics/_backend/_aioca.py +++ b/src/ophyd_async/epics/_backend/_aioca.py @@ -170,9 +170,11 @@ def __init__(self, datatype: Optional[Type[T]], read_pv: str, write_pv: str): self.write_pv = write_pv self.initial_values: Dict[str, AugmentedValue] = {} self.converter: CaConverter = DisconnectedCaConverter(None, None) - self.source = f"ca://{self.read_pv}" self.subscription: Optional[Subscription] = None + def source(self, name: str): + return f"ca://{self.read_pv}" + async def _store_initial_value(self, pv, timeout: float = DEFAULT_TIMEOUT): try: self.initial_values[pv] = await caget( @@ -216,9 +218,9 @@ async def _caget(self, format: Format) -> AugmentedValue: timeout=None, ) - async def get_descriptor(self) -> Descriptor: + async def get_descriptor(self, source: str) -> Descriptor: value = await self._caget(FORMAT_CTRL) - return self.converter.descriptor(self.source, value) + return self.converter.descriptor(source, value) async def get_reading(self) -> Reading: value = await self._caget(FORMAT_TIME) diff --git a/src/ophyd_async/epics/_backend/_p4p.py b/src/ophyd_async/epics/_backend/_p4p.py index 759d86b7bb..586d4cce9b 100644 --- a/src/ophyd_async/epics/_backend/_p4p.py +++ b/src/ophyd_async/epics/_backend/_p4p.py @@ -236,9 +236,12 @@ def __init__(self, datatype: Optional[Type[T]], read_pv: str, write_pv: str): self.write_pv = write_pv self.initial_values: Dict[str, Any] = {} self.converter: PvaConverter = DisconnectedPvaConverter() - self.source = f"pva://{self.read_pv}" self.subscription: Optional[Subscription] = None + @property + def source(self, name: str): + return f"pva://{self.read_pv}" + @property def ctxt(self) -> Context: if PvaSignalBackend._ctxt is None: @@ -290,9 +293,9 @@ async def put(self, value: Optional[T], wait=True, timeout=None): ) raise NotConnected(f"pva://{self.write_pv}") from exc - async def get_descriptor(self) -> Descriptor: + async def get_descriptor(self, source: str) -> Descriptor: value = await self.ctxt.get(self.read_pv) - return self.converter.descriptor(self.source, value) + return self.converter.descriptor(source, value) def _pva_request_string(self, fields: List[str]) -> str: """ diff --git a/src/ophyd_async/epics/pvi/pvi.py b/src/ophyd_async/epics/pvi/pvi.py index ea20656261..881d4f6b24 100644 --- a/src/ophyd_async/epics/pvi/pvi.py +++ b/src/ophyd_async/epics/pvi/pvi.py @@ -172,8 +172,8 @@ def _sim_common_blocks(device: Device, stripped_type: Optional[Type] = None): if is_device_vector: if is_signal: - sub_device_1 = device_cls(SimSignalBackend(signal_dtype, device_name)) - sub_device_2 = device_cls(SimSignalBackend(signal_dtype, device_name)) + sub_device_1 = device_cls(SimSignalBackend(signal_dtype)) + sub_device_2 = device_cls(SimSignalBackend(signal_dtype)) sub_device = DeviceVector({1: sub_device_1, 2: sub_device_2}) else: sub_device = DeviceVector({1: device_cls(), 2: device_cls()}) @@ -185,7 +185,7 @@ def _sim_common_blocks(device: Device, stripped_type: Optional[Type] = None): value.parent = sub_device else: if is_signal: - sub_device = device_cls(SimSignalBackend(signal_dtype, device_name)) + sub_device = device_cls(SimSignalBackend(signal_dtype)) else: sub_device = device_cls() diff --git a/src/ophyd_async/sim/pattern_generator.py b/src/ophyd_async/sim/pattern_generator.py index b6e5434eca..ebd7aed18f 100644 --- a/src/ophyd_async/sim/pattern_generator.py +++ b/src/ophyd_async/sim/pattern_generator.py @@ -54,7 +54,7 @@ def get_full_file_description( ): full_file_description: Dict[str, Descriptor] = {} for d in datasets: - source = f"sim://{d.name}" + source = f"soft://{d.name}" shape = outer_shape + tuple(d.shape) dtype = "number" if d.shape == [1] else "array" descriptor = Descriptor( @@ -158,7 +158,7 @@ def __init__( self.written_images_counter: int = 0 # it automatically initializes to 0 - self.signal_backend = SimSignalBackend(int, "sim://sim_images_counter") + self.signal_backend = SimSignalBackend(int) self.sim_signal = SignalR(self.signal_backend) blob = np.array( generate_gaussian_blob(width=detector_width, height=detector_height) diff --git a/tests/core/test_flyer.py b/tests/core/test_flyer.py index 53ff7313a7..5f6e5f438f 100644 --- a/tests/core/test_flyer.py +++ b/tests/core/test_flyer.py @@ -51,7 +51,7 @@ async def stop(self): class DummyWriter(DetectorWriter): def __init__(self, name: str, shape: Sequence[int]): - self.dummy_signal = SignalRW(backend=SimSignalBackend(int, source="test")) + self.dummy_signal = SignalRW(backend=SimSignalBackend(int)) self._shape = shape self._name = name self._file: Optional[ComposeStreamResourceBundle] = None @@ -61,7 +61,7 @@ def __init__(self, name: str, shape: Sequence[int]): async def open(self, multiplier: int = 1) -> Dict[str, Descriptor]: return { self._name: Descriptor( - source="sim://some-source", + source="soft://some-source", shape=self._shape, dtype="number", external="STREAM:", diff --git a/tests/core/test_signal.py b/tests/core/test_signal.py index 5393cb1a78..f2aa4252be 100644 --- a/tests/core/test_signal.py +++ b/tests/core/test_signal.py @@ -2,15 +2,19 @@ import re import time +import numpy import pytest from ophyd_async.core import ( Signal, + SignalR, SignalRW, SimSignalBackend, set_and_wait_for_value, set_sim_put_proceeds, set_sim_value, + soft_signal_r_and_backend, + soft_signal_rw, wait_for_value, ) from ophyd_async.core.utils import DEFAULT_TIMEOUT @@ -26,7 +30,7 @@ async def connect(self, sim=False, timeout=DEFAULT_TIMEOUT): def test_signals_equality_raises(): - sim_backend = SimSignalBackend(str, "test") + sim_backend = SimSignalBackend(str) s1 = MySignal(sim_backend) s2 = MySignal(sim_backend) @@ -45,7 +49,7 @@ def test_signals_equality_raises(): async def test_set_sim_put_proceeds(): - sim_signal = Signal(SimSignalBackend(str, "test")) + sim_signal = Signal(SimSignalBackend(str)) await sim_signal.connect(sim=True) assert sim_signal._backend.put_proceeds.is_set() is True @@ -63,7 +67,7 @@ async def time_taken_by(coro) -> float: async def test_wait_for_value_with_value(): - sim_signal = SignalRW(SimSignalBackend(str, "test")) + sim_signal = SignalRW(SimSignalBackend(str)) sim_signal.set_name("sim_signal") await sim_signal.connect(sim=True) set_sim_value(sim_signal, "blah") @@ -84,7 +88,7 @@ async def test_wait_for_value_with_value(): async def test_wait_for_value_with_funcion(): - sim_signal = SignalRW(SimSignalBackend(float, "test")) + sim_signal = SignalRW(SimSignalBackend(float)) sim_signal.set_name("sim_signal") await sim_signal.connect(sim=True) set_sim_value(sim_signal, 45.8) @@ -110,7 +114,7 @@ def less_than_42(v): async def test_set_and_wait_for_value(): - sim_signal = SignalRW(SimSignalBackend(int, "test")) + sim_signal = SignalRW(SimSignalBackend(int)) sim_signal.set_name("sim_signal") await sim_signal.connect(sim=True) set_sim_value(sim_signal, 0) @@ -119,3 +123,33 @@ async def test_set_and_wait_for_value(): assert not st.done set_sim_put_proceeds(sim_signal, True) assert await time_taken_by(st) < 0.1 + + +@pytest.mark.parametrize( + "signal_method,signal_class", + [(soft_signal_r_and_backend, SignalR), (soft_signal_rw, SignalRW)], +) +async def test_create_soft_signal(signal_method, signal_class): + SIGNAL_NAME = "TEST-PREFIX:SIGNAL" + INITIAL_VALUE = "INITIAL" + if signal_method == soft_signal_r_and_backend: + signal, backend = signal_method(str, INITIAL_VALUE, SIGNAL_NAME) + elif signal_method == soft_signal_rw: + signal = signal_method(str, INITIAL_VALUE, SIGNAL_NAME) + backend = signal._backend + assert signal.source == f"soft://{SIGNAL_NAME}" + assert isinstance(signal, signal_class) + assert isinstance(signal._backend, SimSignalBackend) + await signal.connect() + assert (await signal.get_value()) == INITIAL_VALUE + # connecting with sim=False uses existing SimSignalBackend + assert signal._backend is backend + + +async def test_soft_signal_numpy(): + float_signal = soft_signal_rw(numpy.float64, numpy.float64(1), "float_signal") + int_signal = soft_signal_rw(numpy.int32, numpy.int32(1), "int_signal") + await float_signal.connect() + await int_signal.connect() + assert (await float_signal.describe())["float_signal"]["dtype"] == "number" + assert (await int_signal.describe())["int_signal"]["dtype"] == "integer" diff --git a/tests/core/test_sim.py b/tests/core/test_sim.py index baefc850ee..a2897ed984 100644 --- a/tests/core/test_sim.py +++ b/tests/core/test_sim.py @@ -93,16 +93,16 @@ async def test_backend_get_put_monitor( put_value: T, descriptor: Callable[[Any], dict], ): - backend = SimSignalBackend(datatype, "") + backend = SimSignalBackend(datatype) await backend.connect() q = MonitorQueue(backend) try: # Check descriptor - assert ( - dict(source="sim://", **descriptor(initial_value)) - == await backend.get_descriptor() - ) + source = "soft://test" + assert dict( + source=source, **descriptor(initial_value) + ) == await backend.get_descriptor(source) # Check initial value await q.assert_updates( pytest.approx(initial_value) if initial_value != "" else initial_value @@ -115,13 +115,13 @@ async def test_backend_get_put_monitor( async def test_sim_backend_if_disconnected(): - sim_backend = SimSignalBackend(npt.NDArray[np.float64], "SOME-IOC:PV") + sim_backend = SimSignalBackend(npt.NDArray[np.float64]) with pytest.raises(NotImplementedError): await sim_backend.get_value() async def test_sim_backend_with_numpy_typing(): - sim_backend = SimSignalBackend(npt.NDArray[np.float64], "SOME-IOC:PV") + sim_backend = SimSignalBackend(npt.NDArray[np.float64]) await sim_backend.connect() array = await sim_backend.get_value() @@ -133,8 +133,8 @@ class myClass: def __init__(self) -> None: pass - sim_signal = Signal(SimSignalBackend(myClass, "test")) + sim_signal = Signal(SimSignalBackend(myClass)) await sim_signal.connect(sim=True) with pytest.raises(AssertionError): - await sim_signal._backend.get_descriptor() + await sim_signal._backend.get_descriptor("") diff --git a/tests/core/test_utils.py b/tests/core/test_utils.py index 6a02bff77f..74ea8bc787 100644 --- a/tests/core/test_utils.py +++ b/tests/core/test_utils.py @@ -24,7 +24,7 @@ async def connect(self, timeout: float = DEFAULT_TIMEOUT): class WorkingDummyChildDevice(Device): def __init__(self, name: str = "working_dummy_child_device") -> None: - self.working_signal = SignalRW(backend=SimSignalBackend(int, "WORKING_SIGNAL")) + self.working_signal = SignalRW(backend=SimSignalBackend(int)) super().__init__(name=name) diff --git a/tests/epics/areadetector/test_single_trigger_det.py b/tests/epics/areadetector/test_single_trigger_det.py index 14d0ea06e8..684f72c3cf 100644 --- a/tests/epics/areadetector/test_single_trigger_det.py +++ b/tests/epics/areadetector/test_single_trigger_det.py @@ -44,9 +44,5 @@ async def test_single_trigger_det(single_trigger_det: SingleTriggerDet, RE: RunE assert names == ["start", "descriptor", "event", "stop"] _, descriptor, event, _ = docs assert descriptor["configuration"]["det"]["data"]["det-drv-acquire_time"] == 0.5 - assert ( - descriptor["data_keys"]["det-stats-unique_id"]["source"] - == "sim://PREFIX:STATSUniqueId_RBV" - ) assert event["data"]["det-drv-array_counter"] == 1 assert event["data"]["det-stats-unique_id"] == 3 diff --git a/tests/epics/areadetector/test_writers.py b/tests/epics/areadetector/test_writers.py index cad363af4b..dda8b74d44 100644 --- a/tests/epics/areadetector/test_writers.py +++ b/tests/epics/areadetector/test_writers.py @@ -40,7 +40,7 @@ async def test_correct_descriptor_doc_after_open(hdf_writer: HDFWriter): assert descriptor == { "test": { - "source": "sim://HDF:FullFileName_RBV", + "source": "soft://hdf-full_file_name", "shape": (10, 10), "dtype": "array", "external": "STREAM:", diff --git a/tests/epics/demo/test_demo.py b/tests/epics/demo/test_demo.py index 832143de99..ba4f941497 100644 --- a/tests/epics/demo/test_demo.py +++ b/tests/epics/demo/test_demo.py @@ -142,9 +142,6 @@ async def test_mover_stopped(sim_mover: demo.Mover): async def test_read_mover(sim_mover: demo.Mover): await sim_mover.stage() assert (await sim_mover.read())["sim_mover"]["value"] == 0.0 - assert (await sim_mover.describe())["sim_mover"][ - "source" - ] == "sim://BLxxI-MO-TABLE-01:X:Readback" assert (await sim_mover.read_configuration())["sim_mover-velocity"]["value"] == 1 assert (await sim_mover.describe_configuration())["sim_mover-units"]["shape"] == [] set_sim_value(sim_mover.readback, 0.5) @@ -158,9 +155,6 @@ async def test_read_mover(sim_mover: demo.Mover): async def test_set_velocity(sim_mover: demo.Mover) -> None: v = sim_mover.velocity - assert (await v.describe())["sim_mover-velocity"][ - "source" - ] == "sim://BLxxI-MO-TABLE-01:X:Velocity" q: asyncio.Queue[Dict[str, Reading]] = asyncio.Queue() v.subscribe(q.put_nowait) assert (await q.get())["sim_mover-velocity"]["value"] == 1.0 @@ -195,9 +189,6 @@ async def test_sensor_disconnected(caplog): async def test_read_sensor(sim_sensor: demo.Sensor): sim_sensor.stage() assert (await sim_sensor.read())["sim_sensor-value"]["value"] == 0 - assert (await sim_sensor.describe())["sim_sensor-value"][ - "source" - ] == "sim://SIM:SENSOR:Value" assert (await sim_sensor.read_configuration())["sim_sensor-mode"][ "value" ] == demo.EnergyMode.low @@ -261,17 +252,17 @@ async def test_dynamic_sensor_group_read_and_describe( "sim_sensor_group-sensors-1-value": { "dtype": "number", "shape": [], - "source": "sim://SIM:SENSOR:1:Value", + "source": "soft://sim_sensor_group-sensors-1-value", }, "sim_sensor_group-sensors-2-value": { "dtype": "number", "shape": [], - "source": "sim://SIM:SENSOR:2:Value", + "source": "soft://sim_sensor_group-sensors-2-value", }, "sim_sensor_group-sensors-3-value": { "dtype": "number", "shape": [], - "source": "sim://SIM:SENSOR:3:Value", + "source": "soft://sim_sensor_group-sensors-3-value", }, } assert reading == { diff --git a/tests/epics/demo/test_demo_ad_sim_detector.py b/tests/epics/demo/test_demo_ad_sim_detector.py index 241f974dec..32e0908de0 100644 --- a/tests/epics/demo/test_demo_ad_sim_detector.py +++ b/tests/epics/demo/test_demo_ad_sim_detector.py @@ -212,15 +212,14 @@ async def test_detector_writes_to_file( async def test_read_and_describe_detector(single_detector: StandardDetector): describe = await single_detector.describe_configuration() read = await single_detector.read_configuration() - assert describe == { "test-drv-acquire_time": { - "source": "sim://TEST:DRV:AcquireTime_RBV", + "source": "soft://test-drv-acquire_time", "dtype": "number", "shape": [], }, "test-drv-acquire": { - "source": "sim://TEST:DRV:Acquire_RBV", + "source": "soft://test-drv-acquire", "dtype": "boolean", "shape": [], }, diff --git a/tests/epics/motion/test_motor.py b/tests/epics/motion/test_motor.py index 32b270d2e7..c91b11aa0c 100644 --- a/tests/epics/motion/test_motor.py +++ b/tests/epics/motion/test_motor.py @@ -81,9 +81,6 @@ async def test_motor_moving_stopped(sim_motor: motor.Motor): async def test_read_motor(sim_motor: motor.Motor): sim_motor.stage() assert (await sim_motor.read())["sim_motor"]["value"] == 0.0 - assert (await sim_motor.describe())["sim_motor"][ - "source" - ] == "sim://BLxxI-MO-TABLE-01:X.RBV" assert (await sim_motor.read_configuration())["sim_motor-velocity"]["value"] == 1 assert (await sim_motor.describe_configuration())["sim_motor-motor_egu"][ "shape" @@ -99,9 +96,6 @@ async def test_read_motor(sim_motor: motor.Motor): async def test_set_velocity(sim_motor: motor.Motor) -> None: v = sim_motor.velocity - assert (await v.describe())["sim_motor-velocity"][ - "source" - ] == "sim://BLxxI-MO-TABLE-01:X.VELO" q: asyncio.Queue[Dict[str, Reading]] = asyncio.Queue() v.subscribe(q.put_nowait) assert (await q.get())["sim_motor-velocity"]["value"] == 1.0 diff --git a/tests/epics/test_signals.py b/tests/epics/test_signals.py index c110c2033b..41c579bf2b 100644 --- a/tests/epics/test_signals.py +++ b/tests/epics/test_signals.py @@ -132,8 +132,10 @@ async def assert_monitor_then_put( q = MonitorQueue(backend) try: # Check descriptor - source = f"{ioc.protocol}://{PV_PREFIX}:{ioc.protocol}:{suffix}" - assert dict(source=source, **descriptor) == await backend.get_descriptor() + pv_name = f"{ioc.protocol}://{PV_PREFIX}:{ioc.protocol}:{suffix}" + assert dict(source=pv_name, **descriptor) == await backend.get_descriptor( + pv_name + ) # Check initial value await q.assert_updates(pytest.approx(initial_value)) # Put to new value and check that @@ -407,7 +409,9 @@ async def test_pva_table(ioc: IOC) -> None: q = MonitorQueue(backend) try: # Check descriptor - dict(source=backend.source, **descriptor) == await backend.get_descriptor() + dict(source="test-source", **descriptor) == await backend.get_descriptor( + "test-source" + ) # Check initial value await q.assert_updates(approx_table(i)) # Put to new value and check that @@ -442,7 +446,7 @@ async def test_pvi_structure(ioc: IOC) -> None: try: # Check descriptor with pytest.raises(NotImplementedError): - await backend.get_descriptor() + await backend.get_descriptor("") # Check initial value await q.assert_updates(expected) await backend.get_value() @@ -469,10 +473,10 @@ async def test_pva_ntdarray(ioc: IOC): for i, p in [(initial, put), (put, initial)]: with closing(MonitorQueue(backend)) as q: assert { - "source": backend.source, + "source": "test-source", "dtype": "array", "shape": [2, 3], - } == await backend.get_descriptor() + } == await backend.get_descriptor("test-source") # Check initial value await q.assert_updates(pytest.approx(i)) await raw_data_backend.put(p.flatten()) @@ -494,8 +498,7 @@ async def test_non_existent_errors(ioc: IOC): backend = await ioc.make_backend(str, "non-existent", connect=False) # Can't use asyncio.wait_for on python3.8 because of # https://github.com/python/cpython/issues/84787 - - with pytest.raises(NotConnected, match=backend.source): + with pytest.raises(NotConnected): await backend.connect(timeout=0.1) diff --git a/tests/panda/test_writer.py b/tests/panda/test_writer.py index c80893823c..ffb50dff4e 100644 --- a/tests/panda/test_writer.py +++ b/tests/panda/test_writer.py @@ -30,10 +30,10 @@ async def sim_panda() -> PandA: sim_panda.block1 = Device("BLOCK1") # type: ignore[attr-defined] sim_panda.block2 = Device("BLOCK2") # type: ignore[attr-defined] sim_panda.block1.test_capture = SignalRW( # type: ignore[attr-defined] - backend=SimSignalBackend(str, source="BLOCK1_capture") + backend=SimSignalBackend(str) ) sim_panda.block2.test_capture = SignalRW( # type: ignore[attr-defined] - backend=SimSignalBackend(str, source="BLOCK2_capture") + backend=SimSignalBackend(str) ) await asyncio.gather( @@ -69,12 +69,8 @@ async def sim_writer(tmp_path, sim_panda) -> PandaHDFWriter: async def test_get_capture_signals_gets_all_signals(sim_panda): async with DeviceCollector(sim=True): sim_panda.test_seq = Device("seq") - sim_panda.test_seq.seq1_capture = SignalR( - backend=SimSignalBackend(str, source="seq1_capture") - ) - sim_panda.test_seq.seq2_capture = SignalR( - backend=SimSignalBackend(str, source="seq2_capture") - ) + sim_panda.test_seq.seq1_capture = SignalR(backend=SimSignalBackend(str)) + sim_panda.test_seq.seq2_capture = SignalR(backend=SimSignalBackend(str)) await asyncio.gather( sim_panda.test_seq.connect(), sim_panda.test_seq.seq1_capture.connect(), @@ -181,7 +177,7 @@ async def test_numeric_blocks_correctly_formated(sim_writer: PandaHDFWriter): async def get_numeric_signal(_): return { "device.block.1": CaptureSignalWrapper( - SignalR(backend=SimSignalBackend(str, source="test_signal")), + SignalR(backend=SimSignalBackend(str)), Capture.Value, ) } diff --git a/tests/sim/test_sim_writer.py b/tests/sim/test_sim_writer.py index 59ecd5a494..d26fd3beaa 100644 --- a/tests/sim/test_sim_writer.py +++ b/tests/sim/test_sim_writer.py @@ -23,13 +23,13 @@ async def test_correct_descriptor_doc_after_open(writer: SimPatternDetectorWrite assert descriptor == { "_entry_data_data": { - "source": "sim:///entry/data/data", + "source": "soft:///entry/data/data", "shape": (1, 240, 320), "dtype": "array", "external": "STREAM:", }, "_entry_sum": { - "source": "sim:///entry/sum", + "source": "soft:///entry/sum", "shape": (1,), "dtype": "array", "external": "STREAM:", diff --git a/tests/test_flyer_with_panda.py b/tests/test_flyer_with_panda.py index f680ad0395..d0cfab8221 100644 --- a/tests/test_flyer_with_panda.py +++ b/tests/test_flyer_with_panda.py @@ -28,7 +28,7 @@ class DummyWriter(DetectorWriter): def __init__(self, name: str, shape: Sequence[int]): - self.dummy_signal = SignalRW(backend=SimSignalBackend(int, source="test")) + self.dummy_signal = SignalRW(backend=SimSignalBackend(int)) self._shape = shape self._name = name self._file: Optional[ComposeStreamResourceBundle] = None @@ -38,7 +38,7 @@ def __init__(self, name: str, shape: Sequence[int]): async def open(self, multiplier: int = 1) -> Dict[str, Descriptor]: return { self._name: Descriptor( - source="sim://some-source", + source="soft://some-source", shape=self._shape, dtype="number", external="STREAM:",