11import asyncio
22import warnings
33from functools import wraps
4- from typing import Any , Callable , Dict , Optional
4+ from typing import Any , Callable , Dict
55
66from bluesky .protocols import DataKey , Reading
77from frappy .client import CacheItem
1717 StructOf ,
1818 TupleOf ,
1919)
20- from ophyd_async .core import Callback , SignalBackend , T
20+ from ophyd_async .core import Callback , SignalBackend , SignalDatatypeT
2121
2222from secop_ophyd .AsyncFrappyClient import AsyncFrappyClient
23- from secop_ophyd .util import Path , SECoPdtype , SECoPReading , deep_get
23+ from secop_ophyd .util import Path , SECoPDataKey , SECoPdtype , SECoPReading , deep_get
2424
2525atomic_dtypes = (
2626 StringType ,
@@ -105,18 +105,18 @@ async def put(self, value: Any | None, wait=True):
105105
106106 async def get_datakey (self , source : str ) -> DataKey :
107107 """Metadata like source, dtype, shape, precision, units"""
108- return self .describe_dict
108+ return describedict_to_datakey ( self .describe_dict )
109109
110- async def get_reading (self ) -> Reading :
110+ async def get_reading (self ) -> Reading [ SignalDatatypeT ] :
111111 return self .reading .get_reading ()
112112
113- async def get_value (self ) -> T :
113+ async def get_value (self ) -> SignalDatatypeT :
114114 return self .reading .get_value ()
115115
116- async def get_setpoint (self ) -> T :
116+ async def get_setpoint (self ) -> SignalDatatypeT :
117117 return await self .get_value ()
118118
119- def set_callback (self , callback : Callback [T ] | None ) -> None :
119+ def set_callback (self , callback : Callback [Reading [ SignalDatatypeT ] ] | None ) -> None :
120120 self .callback = callback # type: ignore[assignment]
121121
122122
@@ -191,36 +191,25 @@ async def put(self, value: Any | None, wait=True):
191191
192192 async def get_datakey (self , source : str ) -> DataKey :
193193 """Metadata like source, dtype, shape, precision, units"""
194- res = {}
195194
196- res [ "source" ] = self .source ("" , True )
195+ return DataKey ( shape = [], dtype = "string" , source = self .source ("" , True ) )
197196
198- # ophyd datatype (some SECoP datatypeshaveto be converted)
199- # signalx has no datatype and is never read
200- res ["dtype" ] = "None"
201-
202- # get shape from datainfo and SECoPtype
203-
204- res ["shape" ] = [] # type: ignore
205-
206- return res
207-
208- async def get_reading (self ) -> Reading :
197+ async def get_reading (self ) -> Reading [SignalDatatypeT ]:
209198 raise Exception (
210199 "Cannot read _x Signal, it has no value and is only"
211200 + " used to trigger Command execution"
212201 )
213202
214- async def get_value (self ) -> T :
203+ async def get_value (self ) -> SignalDatatypeT :
215204 raise Exception (
216205 "Cannot read _x Signal, it has no value and is only"
217206 + " used to trigger Command execution"
218207 )
219208
220- def set_callback (self , callback : Callback [T ] | None ) -> None :
209+ def set_callback (self , callback : Callback [Reading [ SignalDatatypeT ] ] | None ) -> None :
221210 pass
222211
223- async def get_setpoint (self ) -> T :
212+ async def get_setpoint (self ) -> SignalDatatypeT :
224213 raise Exception (
225214 "Cannot read _x Signal, it has no value and is only"
226215 + " used to trigger Command execution"
@@ -334,9 +323,9 @@ async def get_datakey(self, source: str) -> DataKey:
334323 SECoPReading (entry = dataset , secop_dt = self .SECoP_type_info )
335324 self .describe_dict .update (self .SECoP_type_info .get_datakey ())
336325
337- return self .describe_dict
326+ return describedict_to_datakey ( self .describe_dict )
338327
339- async def get_reading (self ) -> Reading :
328+ async def get_reading (self ) -> Reading [ SignalDatatypeT ] :
340329 dataset = await self ._secclient .get_parameter (
341330 ** self .get_param_path (), trycache = False
342331 )
@@ -345,15 +334,15 @@ async def get_reading(self) -> Reading:
345334
346335 return sec_reading .get_reading ()
347336
348- async def get_value (self ) -> T :
337+ async def get_value (self ) -> SignalDatatypeT :
349338 dataset : Reading = await self .get_reading ()
350339
351340 return dataset ["value" ] # type: ignore
352341
353- async def get_setpoint (self ) -> T :
342+ async def get_setpoint (self ) -> SignalDatatypeT :
354343 return await self .get_value ()
355344
356- def set_callback (self , callback : Callback [T ] | None ) -> None :
345+ def set_callback (self , callback : Callback [Reading [ SignalDatatypeT ] ] | None ) -> None :
357346 def awaitify (sync_func ):
358347 """Wrap a synchronous callable to allow ``await``'ing it"""
359348
@@ -403,7 +392,7 @@ class PropertyBackend(SignalBackend):
403392 """Readonly backend for static SECoP Properties of Nodes/Modules"""
404393
405394 def __init__ (
406- self , prop_key : str , property_dict : Dict [str , T ], secclient : AsyncFrappyClient
395+ self , prop_key : str , property_dict : Dict [str , Any ], secclient : AsyncFrappyClient
407396 ) -> None :
408397 """Initializes PropertyBackend
409398
@@ -450,16 +439,16 @@ async def connect(self, timeout: float):
450439 """Connect to underlying hardware"""
451440 pass
452441
453- async def put (self , value : Optional [ T ] , wait = True ):
442+ async def put (self , value : SignalDatatypeT | None , wait = True ):
454443 """Put a value to the PV, if wait then wait for completion for up to timeout"""
455444 # Properties are readonly
456445 pass
457446
458447 async def get_datakey (self , source : str ) -> DataKey :
459448 """Metadata like source, dtype, shape, precision, units"""
460- return self .describe_dict
449+ return describedict_to_datakey ( self .describe_dict )
461450
462- async def get_reading (self ) -> Reading :
451+ async def get_reading (self ) -> Reading [ SignalDatatypeT ] :
463452 dataset = CacheItem (
464453 value = self ._prop_value , timestamp = self ._secclient .conn_timestamp
465454 )
@@ -468,15 +457,15 @@ async def get_reading(self) -> Reading:
468457
469458 return sec_reading .get_reading ()
470459
471- async def get_value (self ) -> T :
460+ async def get_value (self ) -> SignalDatatypeT :
472461 dataset : Reading = await self .get_reading ()
473462
474463 return dataset ["value" ] # type: ignore
475464
476- async def get_setpoint (self ) -> T :
465+ async def get_setpoint (self ) -> SignalDatatypeT :
477466 return await self .get_value ()
478467
479- def set_callback (self , callback : Callback [T ] | None ) -> None :
468+ def set_callback (self , callback : Callback [Reading [ SignalDatatypeT ] ] | None ) -> None :
480469 pass
481470
482471
@@ -515,3 +504,27 @@ def secop_dtype_obj_from_json(prop_val):
515504 f"""unsupported datatype in Property: { str (prop_val .__class__ .__name__ )} \n
516505 propval: { prop_val } """
517506 )
507+
508+
509+ def describedict_to_datakey (describe_dict : dict ) -> SECoPDataKey :
510+ """Convert a DataKey to a SECoPDataKey"""
511+ datakey = SECoPDataKey (
512+ dtype = describe_dict ["dtype" ],
513+ shape = describe_dict ["shape" ],
514+ source = describe_dict ["source" ],
515+ SECOP_datainfo = describe_dict ["SECOP_datainfo" ],
516+ )
517+
518+ if "units" in describe_dict :
519+ datakey ["units" ] = describe_dict ["units" ]
520+
521+ if "dtype_str" in describe_dict :
522+ datakey ["dtype_str" ] = describe_dict ["dtype_str" ]
523+
524+ if "dtype_descr" in describe_dict :
525+ datakey ["dtype_descr" ] = describe_dict ["dtype_descr" ]
526+
527+ if "dtype_numpy" in describe_dict :
528+ datakey ["dtype_numpy" ] = describe_dict ["dtype_numpy" ]
529+
530+ return datakey
0 commit comments