diff --git a/pyproject.toml b/pyproject.toml index cf4c27e..641c97b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ version = "0.0.1" description = "An Interface between bluesky and SECoP, using ophyd and frappy-client" dependencies = [ - 'ophyd-async == 0.7.0', + 'ophyd-async == 0.8.0', 'frappy-core@git+https://github.com/SampleEnvironment/frappy@v0.19.2' ] @@ -93,6 +93,7 @@ exclude = [".tox", "venv","frappy"] [tool.mypy] ignore_missing_imports = true # Ignore missing stubs in imported modules plugins = ["numpy.typing.mypy_plugin"] +check_untyped_defs = true [tool.black] diff --git a/src/secop_ophyd/SECoPDevices.py b/src/secop_ophyd/SECoPDevices.py index a8a0fa2..7070611 100644 --- a/src/secop_ophyd/SECoPDevices.py +++ b/src/secop_ophyd/SECoPDevices.py @@ -34,17 +34,14 @@ ) from ophyd_async.core import ( AsyncStatus, - ConfigSignal, - HintedSignal, SignalR, SignalRW, SignalX, StandardReadable, - T, + StandardReadableFormat, observe_value, ) from ophyd_async.core._utils import Callback -from typing_extensions import Self from secop_ophyd.AsyncFrappyClient import AsyncFrappyClient from secop_ophyd.GenNodeCode import GenNodeCode, Method @@ -125,7 +122,7 @@ def __init__(self, secclient: AsyncFrappyClient) -> None: self._secclient: AsyncFrappyClient = secclient - self.status: SignalR = None + self.status: SignalR self.impl: str | None = None @@ -248,46 +245,54 @@ def __init__(self, path: Path, secclient: AsyncFrappyClient): self.wait_idle: bool = False - # Argument Signals (config Signals, can also be read) - arg_path = path.append("argument") - if self.arg_dtype is None: - self.argument = None - else: - arg_backend = LocalBackend( - path=arg_path, - secop_dtype_obj=self.arg_dtype, - sig_datainfo=datainfo["argument"], - ) - self.argument = SignalRW(arg_backend) - config.append(self.argument) - - # Result Signals (read Signals) - res_path = path.append("result") - - if self.res_dtype is None: - self.result = None - else: - res_backend = LocalBackend( - path=res_path, - secop_dtype_obj=self.res_dtype, - sig_datainfo=datainfo["result"], + with self.add_children_as_readables( + format=StandardReadableFormat.CONFIG_SIGNAL + ): + # Argument Signals (config Signals, can also be read) + arg_path = path.append("argument") + if self.arg_dtype is None: + self.argument = None + else: + arg_backend = LocalBackend( + path=arg_path, + secop_dtype_obj=self.arg_dtype, + sig_datainfo=datainfo["argument"], + ) + self.argument = SignalRW(arg_backend) + config.append(self.argument) + + # Result Signals (read Signals) + res_path = path.append("result") + + if self.res_dtype is None: + self.result = None + else: + res_backend = LocalBackend( + path=res_path, + secop_dtype_obj=self.res_dtype, + sig_datainfo=datainfo["result"], + ) + self.result = SignalRW(res_backend) + read.append(self.argument) + + argument = None + result = None + if isinstance(self.argument, SignalR): + argument = self.argument._connector.backend + + if isinstance(self.result, SignalR): + result = self.result._connector.backend + + # SignalX (signal that triggers execution of the Command) + exec_backend = SECoPXBackend( + path=path, + secclient=secclient, + argument=argument, # type: ignore + result=result, # type: ignore ) - self.result = SignalRW(res_backend) - read.append(self.argument) - - # SignalX (signal that triggers execution of the Command) - exec_backend = SECoPXBackend( - path=path, - secclient=secclient, - argument=None if self.argument is None else self.argument._backend, - result=None if self.result is None else self.result._backend, - ) self.commandx = SignalX(exec_backend) - self.add_readables(read, wrapper=HintedSignal) - self.add_readables(config, wrapper=ConfigSignal) - super().__init__(name=dev_name) def trigger(self) -> AsyncStatus: @@ -352,10 +357,12 @@ def __init__(self, secclient: AsyncFrappyClient, module_name: str): module_desc = secclient.modules[module_name] self.plans: list[Method] = [] self.mod_prop_devices: Dict[str, SignalR] = {} - self.param_devices: Dict[str, T] = {} + self.param_devices: Dict[str, Any] = {} # Add configuration Signal - with self.add_children_as_readables(ConfigSignal): + with self.add_children_as_readables( + format=StandardReadableFormat.CONFIG_SIGNAL + ): # generate Signals from Module Properties for property in module_desc["properties"]: propb = PropertyBackend(property, module_desc["properties"], secclient) @@ -387,7 +394,9 @@ def __init__(self, secclient: AsyncFrappyClient, module_name: str): self.param_devices[parameter] = getattr(self, parameter) # Add readables Signals - with self.add_children_as_readables(HintedSignal): + with self.add_children_as_readables( + format=StandardReadableFormat.HINTED_SIGNAL + ): for parameter in READABLE_PARAMS: if parameter not in module_desc["parameters"].keys(): continue @@ -465,8 +474,13 @@ def wait_for_idle_factory(): yield from bps.wait_for([wait_for_idle_factory]) - if return_type is not None and cmd_dev.result is not None: - return cmd_dev.result._backend.reading.get_value() + if ( + return_type is not None + and isinstance(cmd_dev.result, SignalR) + and isinstance(cmd_dev.result._connector.backend, LocalBackend) + ): + + return cmd_dev.result._connector.backend.reading.get_value() def command_plan(self, arg, wait_for_idle: bool = False): # TODO Type checking @@ -485,8 +499,13 @@ def wait_for_idle_factory(): yield from bps.wait_for([wait_for_idle_factory]) - if return_type is not None and cmd_dev.result is not None: - return cmd_dev.result._backend.reading.get_value() + if ( + return_type is not None + and isinstance(cmd_dev.result, SignalR) + and isinstance(cmd_dev.result._connector.backend, LocalBackend) + ): + + return cmd_dev.result._connector.backend.reading.get_value() cmd_meth = command_plan_no_arg if argument_type is None else command_plan @@ -511,7 +530,7 @@ def wait_for_idle_factory(): return cmd_meth - def trigger(self) -> bps.Status: + def trigger(self) -> AsyncStatus: return AsyncStatus(awaitable=self.value.read(cached=False)) def subscribe(self, function: Callback[dict[str, Reading]]) -> None: @@ -715,14 +734,16 @@ def __init__(self, secclient: AsyncFrappyClient): config = [] - with self.add_children_as_readables(ConfigSignal): + with self.add_children_as_readables( + format=StandardReadableFormat.CONFIG_SIGNAL + ): for property in self._secclient.properties: propb = PropertyBackend(property, self._secclient.properties, secclient) setattr(self, property, SignalR(backend=propb)) config.append(getattr(self, property)) self.node_prop_devices[property] = getattr(self, property) - with self.add_children_as_readables(): + with self.add_children_as_readables(format=StandardReadableFormat.CHILD): for module, module_desc in self._secclient.modules.items(): secop_dev_class = class_from_interface(module_desc["properties"]) @@ -738,7 +759,7 @@ def __init__(self, secclient: AsyncFrappyClient): super().__init__(name=name) @classmethod - def create(cls, host: str, port: str, loop, log=Logger) -> Self: + def create(cls, host: str, port: str, loop, log=Logger) -> "SECoPNodeDevice": secclient: AsyncFrappyClient @@ -762,7 +783,9 @@ def create(cls, host: str, port: str, loop, log=Logger) -> Self: return SECoPNodeDevice(secclient=secclient) @classmethod - async def create_async(cls, host: str, port: str, loop, log=Logger) -> Self: + async def create_async( + cls, host: str, port: str, loop, log=Logger + ) -> "SECoPNodeDevice": secclient: AsyncFrappyClient @@ -930,7 +953,7 @@ def descriptiveDataChange(self, module, description): # noqa: N802 setattr(self, property, SignalR(backend=propb)) config.append(getattr(self, property)) - self.add_readables(config, wrapper=ConfigSignal) + self.add_readables(config, format=StandardReadableFormat.CONFIG_SIGNAL) else: # Refresh changed modules module_desc = self._secclient.modules[module] diff --git a/src/secop_ophyd/SECoPSignal.py b/src/secop_ophyd/SECoPSignal.py index 8e3f9b1..6a62bb0 100644 --- a/src/secop_ophyd/SECoPSignal.py +++ b/src/secop_ophyd/SECoPSignal.py @@ -17,7 +17,7 @@ StructOf, TupleOf, ) -from ophyd_async.core import SignalBackend, T +from ophyd_async.core import Callback, SignalBackend, T from secop_ophyd.AsyncFrappyClient import AsyncFrappyClient from secop_ophyd.util import Path, SECoPdtype, SECoPReading, deep_get @@ -32,6 +32,7 @@ ArrayOf, ) + # max depth for datatypes supported by tiled/databroker MAX_DEPTH = 1 @@ -69,7 +70,7 @@ def __init__( # TODO check if this is really needed self.datainfo: dict = sig_datainfo - self.callback: Callable[[Reading, Any], None] | None = None + self.callback: Callback | None = None self.SECoPdtype_obj: DataType = secop_dtype_obj @@ -79,7 +80,7 @@ def __init__( self.describe_dict = {} - self.describe_dict["source"] = self.source("") + self.describe_dict["source"] = self.source("", True) self.describe_dict.update(self.SECoP_type_info.get_datakey()) @@ -88,17 +89,19 @@ def __init__( property_name = "SECoP_dtype" self.describe_dict[property_name] = prop_val - def source(self, name: str) -> str: + super().__init__(datatype=self.SECoP_type_info.np_datatype) + + def source(self, name: str, read: bool) -> str: return self.source_name - async def connect(self): + async def connect(self, timeout: float): pass - async def put(self, value: Any | None, wait=True, timeout=None): + async def put(self, value: Any | None, wait=True): self.reading.set_reading(self.SECoP_type_info.val2secop(value)) if self.callback is not None: - self.callback(self.reading.get_reading(), self.reading.get_value()) + self.callback(self.reading.get_reading()) async def get_datakey(self, source: str) -> DataKey: """Metadata like source, dtype, shape, precision, units""" @@ -110,8 +113,11 @@ async def get_reading(self) -> Reading: async def get_value(self) -> T: return self.reading.get_value() - def set_callback(self, callback: Callable[[Reading, Any], None] | None) -> None: - self.callback = callback + async def get_setpoint(self) -> T: + return await self.get_value() + + def set_callback(self, callback: Callback[T] | None) -> None: + self.callback = callback # type: ignore[assignment] # TODO add return of Asyncstatus @@ -150,14 +156,15 @@ def __init__( self.result: LocalBackend | None = result self.source_name = self.path._module_name + ":" + self.path._accessible_name + super().__init__(datatype=None) - def source(self, name: str) -> str: + def source(self, name: str, read: bool) -> str: return self.source_name - async def connect(self): + async def connect(self, timeout: float): pass - async def put(self, value: Any | None, wait=True, timeout=None): + async def put(self, value: Any | None, wait=True): if self.argument is None: argument = None @@ -170,7 +177,7 @@ async def put(self, value: Any | None, wait=True, timeout=None): command=self.path._accessible_name, argument=argument, ), - timeout=timeout, + timeout=None, ) # write return Value to corresponding Backend @@ -186,7 +193,7 @@ async def get_datakey(self, source: str) -> DataKey: """Metadata like source, dtype, shape, precision, units""" res = {} - res["source"] = self.source("") + res["source"] = self.source("", True) # ophyd datatype (some SECoP datatypeshaveto be converted) # signalx has no datatype and is never read @@ -210,9 +217,15 @@ async def get_value(self) -> T: + " used to trigger Command execution" ) - def set_callback(self, callback: Callable[[Reading, Any], None] | None) -> None: + def set_callback(self, callback: Callback[T] | None) -> None: pass + async def get_setpoint(self) -> T: + raise Exception( + "Cannot read _x Signal, it has no value and is only" + + " used to trigger Command execution" + ) + class SECoPParamBackend(SignalBackend): """Standard backend for a Signal that represents SECoP Parameter""" @@ -225,6 +238,7 @@ def __init__(self, path: Path, secclient: AsyncFrappyClient) -> None: :param secclient: SECoP client providing communication to the SEC Node :type secclient: AsyncFrappyClient """ + # secclient self._secclient: AsyncFrappyClient = secclient @@ -240,7 +254,6 @@ def __init__(self, path: Path, secclient: AsyncFrappyClient) -> None: self.readonly = self._param_description.get("readonly") - self.datatype: str self.SECoPdtype_str: str self.SECoPdtype_obj: DataType = self._param_description["datatype"] @@ -287,19 +300,23 @@ def __init__(self, path: Path, secclient: AsyncFrappyClient) -> None: property_name = "units" self.describe_dict[property_name] = prop_val - def source(self, name: str) -> str: + super().__init__(datatype=self.SECoP_type_info.np_datatype) + + def source(self, name: str, read: bool) -> str: return self.source_name - async def connect(self): + async def connect(self, timeout: float): pass - async def put(self, value: Any | None, wait=True, timeout=None): + async def put(self, value: Any | None, wait=True): # convert to frappy compatible Format secop_val = self.SECoP_type_info.val2secop(value) + # frappy client has no ability to just send a secop message without + # waiting for a reply await asyncio.wait_for( self._secclient.set_parameter(**self.get_param_path(), value=secop_val), - timeout=timeout, + timeout=None, ) async def get_datakey(self, source: str) -> DataKey: @@ -333,7 +350,10 @@ async def get_value(self) -> T: return dataset["value"] # type: ignore - def set_callback(self, callback: Callable[[Reading, Any], None] | None) -> None: + async def get_setpoint(self) -> T: + return await self.get_value() + + def set_callback(self, callback: Callback[T] | None) -> None: def awaitify(sync_func): """Wrap a synchronous callable to allow ``await``'ing it""" @@ -348,7 +368,7 @@ def updateItem(module, parameter, entry: CacheItem): # noqa: N802 async_callback = awaitify(callback) asyncio.run_coroutine_threadsafe( - async_callback(reading=data.get_reading(), value=data.get_value()), + async_callback(reading=data.get_reading()), self._secclient.loop, ) @@ -421,14 +441,16 @@ def __init__( self._secclient: AsyncFrappyClient = secclient # TODO full property path - def source(self, name: str) -> str: + super().__init__(datatype=self.SECoP_type_info.np_datatype) + + def source(self, name: str, read: bool) -> str: return str(self.source_name) - async def connect(self): + async def connect(self, timeout: float): """Connect to underlying hardware""" pass - async def put(self, value: Optional[T], wait=True, timeout=None): + async def put(self, value: Optional[T], wait=True): """Put a value to the PV, if wait then wait for completion for up to timeout""" # Properties are readonly pass @@ -451,7 +473,10 @@ async def get_value(self) -> T: return dataset["value"] # type: ignore - def set_callback(self, callback: Callable[[Reading, Any], None] | None) -> None: + async def get_setpoint(self) -> T: + return await self.get_value() + + def set_callback(self, callback: Callback[T] | None) -> None: pass @@ -481,9 +506,9 @@ def secop_dtype_obj_from_json(prop_val): members = secop_dtype_obj_from_json(prop_val[0]) return ArrayOf(members) else: - members = [] + members = [] # type: ignore for elem in prop_val: - members.append(secop_dtype_obj_from_json(elem)) + members.append(secop_dtype_obj_from_json(elem)) # type: ignore return TupleOf(*members) raise Exception( diff --git a/src/secop_ophyd/util.py b/src/secop_ophyd/util.py index a1c76cf..983bc49 100644 --- a/src/secop_ophyd/util.py +++ b/src/secop_ophyd/util.py @@ -10,6 +10,7 @@ import numpy as np from bluesky.protocols import Reading +from event_model import DataKey from frappy.client import CacheItem from frappy.datatypes import ( ArrayOf, @@ -24,6 +25,7 @@ StructOf, TupleOf, ) +from ophyd_async.core._utils import StrictEnum SCALAR_DATATYPES = ( IntRange, @@ -94,7 +96,7 @@ def get_memberinfo_path(self): chain( *[ ( - [k] + self._dev_path[i : i + n] + [k] + self._dev_path[i : i + n] # type: ignore if len(self._dev_path[i : i + n]) == n else self._dev_path[i : i + n] ) @@ -109,13 +111,13 @@ def get_signal_name(self): if self._dev_path == []: return self._accessible_name - sig_name_postfix = self._dev_path[self._last_named_param :] + sig_postfix = self._dev_path[self._last_named_param :] if self._last_named_param is None: - sig_name_postfix = [self._accessible_name] + sig_name_postfix + sig_postfix = [self._accessible_name] + sig_postfix # type: ignore delim = "-" - return delim.join(map(str, sig_name_postfix)) + return delim.join(map(str, sig_postfix)) def get_param_desc_path(self): return [self._module_name, "parameters", self._accessible_name] @@ -535,6 +537,7 @@ def make_secop_compatible_object(self, value: np.ndarray) -> Any: class SECoPdtype: + def __init__(self, datatype: DataType) -> None: self.raw_dtype: DataType = datatype @@ -554,6 +557,8 @@ def __init__(self, datatype: DataType) -> None: # Shape of Data self.shape = [] + self.np_datatype: Any + # Describe Fields ------------------------ self.numpy_dtype: np.dtype @@ -593,17 +598,21 @@ def __init__(self, datatype: DataType) -> None: self.dtype = "array" self.dtype_str = self.numpy_dtype.str self.dtype_descr = self.numpy_dtype.descr + self.np_datatype = np.ndarray # Scalar atomic Datatypes and arrays of atomic dataypes else: if self._is_array: # root secop datatype that is contained in the array self.dtype = "array" + self.np_datatype = np.ndarray + # Primitive datatypes else: - self.dtype = SECOP2DTYPE[datatype.__class__] + self.np_datatype = SECOP2DTYPE[datatype.__class__][0] + self.dtype = SECOP2DTYPE[datatype.__class__][1] - def get_datakey(self): + def get_datakey(self) -> DataKey: describe_dict: dict = {} # Composite Datatypes & Arrays of COmposite Datatypes if self._is_composite: @@ -711,11 +720,11 @@ def set_reading(self, value) -> None: SECOP2DTYPE = { - FloatRange: "number", - IntRange: "number", - ScaledInteger: "number", - BoolType: "boolean", - EnumType: "number", - StringType: "string", - BLOBType: "string", + FloatRange: (float, "number"), + IntRange: (int, "integer"), + ScaledInteger: (int, "integer"), + BoolType: (bool, "boolean"), + EnumType: (StrictEnum, "string"), + StringType: (str, "string"), + BLOBType: (str, "string"), } diff --git a/tests/conftest.py b/tests/conftest.py index f68f8fc..1a41be9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="attr-defined" import asyncio import logging import os diff --git a/tests/test_ classgen.py b/tests/test_ classgen.py index 6aaa6f5..d94f247 100644 --- a/tests/test_ classgen.py +++ b/tests/test_ classgen.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="attr-defined" import os from secop_ophyd.SECoPDevices import SECoPNodeDevice diff --git a/tests/test_Node.py b/tests/test_Node.py index ba8ccbf..413229f 100644 --- a/tests/test_Node.py +++ b/tests/test_Node.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="attr-defined" import asyncio import numpy as np @@ -29,7 +30,7 @@ async def test_node_describe(cryo_sim, cryo_node_internal_loop: SECoPNodeDevice) async def test_node_module_describe(cryo_sim, cryo_node_internal_loop: SECoPNodeDevice): - # Node device has no read value, it has to return an empty dict + val_desc = await cryo_node_internal_loop.cryo.describe_configuration() conf = await cryo_node_internal_loop.cryo.read_configuration() @@ -39,16 +40,20 @@ async def test_node_module_describe(cryo_sim, cryo_node_internal_loop: SECoPNode async def test_dev_read(cryo_sim, cryo_node_internal_loop: SECoPNodeDevice): - # Node device has no read value, it has to return an empty dict + cryo_dev: SECoPMoveableDevice = cryo_node_internal_loop.cryo cryo_val = await cryo_dev.read() val_name = cryo_dev.value.name - assert cryo_val[val_name].get("value") > 5 + + read_val = cryo_val[val_name].get("value") + + assert read_val is not None + assert read_val > 5 await cryo_node_internal_loop.disconnect_async() async def test_signal_read(cryo_sim, cryo_node_internal_loop: SECoPNodeDevice): - # Node device has no read value, it has to return an empty dict + cryo_dev: SECoPMoveableDevice = cryo_node_internal_loop.cryo p = await cryo_dev.p.get_value(cached=False) @@ -58,7 +63,7 @@ async def test_signal_read(cryo_sim, cryo_node_internal_loop: SECoPNodeDevice): async def test_signal_read_cached(cryo_sim, cryo_node_internal_loop: SECoPNodeDevice): - # Node device has no read value, it has to return an empty dict + cryo_dev: SECoPMoveableDevice = cryo_node_internal_loop.cryo p = await cryo_dev.p.get_value(cached=True) @@ -71,7 +76,7 @@ async def test_signal_read_cached(cryo_sim, cryo_node_internal_loop: SECoPNodeDe async def test_signal_stage_unstage_read_cached( cryo_sim, cryo_node_internal_loop: SECoPNodeDevice ): - # Node device has no read value, it has to return an empty dict + cryo_dev: SECoPMoveableDevice = cryo_node_internal_loop.cryo await cryo_dev.value.stage() @@ -90,24 +95,18 @@ async def test_signal_stage_unstage_read_cached( async def test_status(cryo_sim, cryo_node_internal_loop: SECoPNodeDevice): - # Node device has no read value, it has to return an empty dict + cryo_dev: SECoPMoveableDevice = cryo_node_internal_loop.cryo status: SignalR = cryo_dev.status - stat_reading = await status.read() - - stat_val = stat_reading[status.name].get("value") - async for current_stat in observe_value(status): + assert current_stat["f0"] == 100 + if current_stat["f0"] == 100: break - print(stat_val["f0"]) - await cryo_node_internal_loop.disconnect_async() - async def test_trigger(cryo_sim, cryo_node_internal_loop: SECoPNodeDevice): - # Node device has no read value, it has to return an empty dict cryo_dev: SECoPMoveableDevice = cryo_node_internal_loop.cryo val_old = await cryo_dev.read() @@ -155,11 +154,9 @@ async def test_node_drive(cryo_sim, cryo_node_internal_loop: SECoPNodeDevice): await stat - reading = await cryo_dev.read() + reading = await cryo_dev.value.get_value() - assert np.isclose( - reading.get(cryo_dev.value.name).get("value"), new_target, atol=0.2 - ) + assert np.isclose(reading, new_target, atol=0.2) await cryo_node_internal_loop.disconnect_async() diff --git a/tests/test_RE.py b/tests/test_RE.py index 1f004f6..a0d625f 100644 --- a/tests/test_RE.py +++ b/tests/test_RE.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="attr-defined" import warnings from bluesky.plans import count diff --git a/tests/test_async_frappy_client.py b/tests/test_async_frappy_client.py index 4956108..0fbbf9b 100644 --- a/tests/test_async_frappy_client.py +++ b/tests/test_async_frappy_client.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="attr-defined" import asyncio from frappy.client import CacheItem diff --git a/tests/test_commands.py b/tests/test_commands.py index bf6643e..b6857ab 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="attr-defined" import asyncio from bluesky.protocols import Triggerable @@ -56,7 +57,7 @@ async def test_struct_inp_cmd(nested_struct_sim, nested_node: SECoPNodeDevice): await test_cmd.argument.set(input_dict) # type: ignore - res: SignalR = test_cmd.result + res: SignalR = test_cmd.result # type: ignore run_obj: SignalX = test_cmd.commandx @@ -86,7 +87,7 @@ async def test_secop_error_on_cmd(nested_struct_sim, nested_node: SECoPNodeDevic await test_cmd.argument.set(input_dict) # type: ignore - res: SignalR = test_cmd.result + res: SignalR = test_cmd.result # type: ignore run_obj: SignalX = test_cmd.commandx @@ -114,7 +115,7 @@ async def test_secop_triggering_cmd_dev( await test_cmd.argument.set(input_dict) # type: ignore - res: SignalR = test_cmd.result + res: SignalR = test_cmd.result # type: ignore stat = test_cmd.trigger() diff --git a/tests/test_dtype.py b/tests/test_dtype.py index 062856f..3c29757 100644 --- a/tests/test_dtype.py +++ b/tests/test_dtype.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="attr-defined" import pytest from frappy.client import CacheItem from frappy.datatypes import ArrayOf, FloatRange, StringType, StructOf, TupleOf diff --git a/tests/test_nested.py b/tests/test_nested.py index d175106..fb289ee 100644 --- a/tests/test_nested.py +++ b/tests/test_nested.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="attr-defined" import numpy as np from ophyd_async.core import SignalR, SignalRW diff --git a/tests/test_path.py b/tests/test_path.py index bd68a0d..f5ca6e4 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="attr-defined" from secop_ophyd.util import Path, deep_get @@ -30,13 +31,13 @@ def test_path_memberinfo(nested_param_description): path_struct = path.append("pos_struct") - datainfo: dict = deep_get(param_desc["datainfo"], path_struct.get_memberinfo_path()) + datainfo = deep_get(param_desc["datainfo"], path_struct.get_memberinfo_path()) assert datainfo == param_desc["datainfo"]["members"]["pos_struct"] path_tupl = path.append("tupl") - datainfo: dict = deep_get(param_desc["datainfo"], path_tupl.get_memberinfo_path()) + datainfo = deep_get(param_desc["datainfo"], path_tupl.get_memberinfo_path()) assert datainfo == param_desc["datainfo"]["members"]["tupl"] @@ -44,7 +45,7 @@ def test_path_memberinfo(nested_param_description): assert path_tupl_2.get_memberinfo_path() == ["members", "tupl", "members", 1] - datainfo: dict = deep_get(param_desc["datainfo"], path_tupl_2.get_memberinfo_path()) + datainfo = deep_get(param_desc["datainfo"], path_tupl_2.get_memberinfo_path()) assert datainfo == param_desc["datainfo"]["members"]["tupl"]["members"][1] diff --git a/tests/test_primitive_arrays.py b/tests/test_primitive_arrays.py index 30eeb5f..81b7038 100644 --- a/tests/test_primitive_arrays.py +++ b/tests/test_primitive_arrays.py @@ -1,3 +1,5 @@ +# mypy: disable-error-code="attr-defined" + import pytest from bluesky import RunEngine from bluesky.callbacks.best_effort import BestEffortCallback