From fd480a791d5b844f30183a6a1bbe8954c7670a25 Mon Sep 17 00:00:00 2001 From: James Souter Date: Fri, 19 Apr 2024 08:04:27 +0000 Subject: [PATCH] Support numpy floating and integer dtypes in SimConverter --- src/ophyd_async/core/signal.py | 22 ++++++++++------------ src/ophyd_async/core/sim_signal_backend.py | 12 +++++++++--- tests/core/test_signal.py | 4 ++-- tests/core/test_sim.py | 7 +++---- tests/panda/test_writer.py | 8 ++------ 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/ophyd_async/core/signal.py b/src/ophyd_async/core/signal.py index a9c76af3f4..f206803475 100644 --- a/src/ophyd_async/core/signal.py +++ b/src/ophyd_async/core/signal.py @@ -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 - ) + self._backend = SimSignalBackend(datatype=self._init_backend.datatype) _sim_backends[self] = self._backend else: self._backend = self._init_backend @@ -254,22 +252,21 @@ def set_sim_callback(signal: Signal[T], callback: ReadingValueCallback[T]) -> No def soft_signal_rw( - datatype: Optional[Type[T]], - name: str, + 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) - ) - signal.set_name(name) + 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]], - name: str, + 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 @@ -277,7 +274,8 @@ def soft_signal_r_and_backend( """ backend = SimSignalBackend(datatype, initial_value) signal = SignalR(backend) - signal.set_name(name) + if name is not None: + signal.set_name(name) return (signal, backend) diff --git a/src/ophyd_async/core/sim_signal_backend.py b/src/ophyd_async/core/sim_signal_backend.py index 267caaa612..1c3e10ce83 100644 --- a/src/ophyd_async/core/sim_signal_backend.py +++ b/src/ophyd_async/core/sim_signal_backend.py @@ -8,6 +8,7 @@ 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 @@ -36,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: diff --git a/tests/core/test_signal.py b/tests/core/test_signal.py index 6796248a06..53c5709fd2 100644 --- a/tests/core/test_signal.py +++ b/tests/core/test_signal.py @@ -132,9 +132,9 @@ 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, SIGNAL_NAME, INITIAL_VALUE) + signal, backend = signal_method(str, INITIAL_VALUE, SIGNAL_NAME) elif signal_method == soft_signal_rw: - signal = signal_method(str, SIGNAL_NAME, INITIAL_VALUE) + signal = signal_method(str, INITIAL_VALUE, SIGNAL_NAME) backend = signal._backend assert signal.source == f"soft://{SIGNAL_NAME}" assert isinstance(signal, signal_class) diff --git a/tests/core/test_sim.py b/tests/core/test_sim.py index d02ed4ae1a..a2897ed984 100644 --- a/tests/core/test_sim.py +++ b/tests/core/test_sim.py @@ -100,10 +100,9 @@ async def test_backend_get_put_monitor( try: # Check descriptor source = "soft://test" - assert ( - dict(source=source, **descriptor(initial_value)) - == await backend.get_descriptor(source) - ) + 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 diff --git a/tests/panda/test_writer.py b/tests/panda/test_writer.py index 8a9064edc4..ffb50dff4e 100644 --- a/tests/panda/test_writer.py +++ b/tests/panda/test_writer.py @@ -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) - ) - sim_panda.test_seq.seq2_capture = SignalR( - backend=SimSignalBackend(str) - ) + 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(),