11import asyncio
22from collections import defaultdict
3- from collections .abc import Callable
3+ from collections .abc import Callable , Coroutine
44from concurrent .futures import Future
5- from types import MethodType
65
76from softioc .asyncio_dispatcher import AsyncioDispatcher
87
8+ from fastcs .datatypes import T
9+
910from .attributes import AttrR , AttrW , Sender , Updater
10- from .controller import Controller
11+ from .controller import BaseController , Controller
1112from .exceptions import FastCSException
1213from .mapping import Mapping , SingleMapping
1314
15+ Callback = Callable [[], Coroutine [None , None , None ]]
16+
1417
1518class Backend :
1619 def __init__ (
1720 self , controller : Controller , loop : asyncio .AbstractEventLoop | None = None
1821 ):
1922 self ._dispatcher = AsyncioDispatcher (loop )
20- self ._loop = self ._dispatcher .loop
23+ self ._loop : asyncio . AbstractEventLoop = self ._dispatcher .loop # type: ignore
2124 self ._controller = controller
2225
2326 self ._initial_tasks = [controller .connect ]
@@ -58,20 +61,20 @@ def _start_scan_tasks(self):
5861 for task in scan_tasks :
5962 asyncio .run_coroutine_threadsafe (task (), self ._loop )
6063
61- def _run (self ):
64+ def _run (self ) -> None :
6265 raise NotImplementedError ("Specific Backend must implement _run" )
6366
6467
65- def _link_single_controller_put_tasks (single_mapping : SingleMapping ) -> None :
66- for name , method in single_mapping .put_methods .items ():
68+ def _link_single_controller_put_tasks (
69+ single_mapping : SingleMapping ,
70+ ) -> None :
71+ for name , put in single_mapping .put_methods .items ():
6772 name = name .removeprefix ("put_" )
6873
6974 attribute = single_mapping .attributes [name ]
7075 match attribute :
7176 case AttrW ():
72- attribute .set_process_callback (
73- MethodType (method .fn , single_mapping .controller )
74- )
77+ attribute .set_process_callback (put )
7578 case _:
7679 raise FastCSException (
7780 f"Mode { attribute .access_mode } does not "
@@ -89,17 +92,28 @@ def _link_attribute_sender_class(single_mapping: SingleMapping) -> None:
8992
9093 callback = _create_sender_callback (attribute , single_mapping .controller )
9194 attribute .set_process_callback (callback )
95+ case _:
96+ pass
9297
9398
94- def _create_sender_callback (attribute , controller ):
95- async def callback (value ):
96- await attribute .sender .put (controller , attribute , value )
99+ def _create_sender_callback (
100+ attribute : AttrW [T ], controller : BaseController
101+ ) -> Callable [[T ], Coroutine [None , None , None ]]:
102+ match attribute .sender :
103+ case Sender () as sender :
97104
98- return callback
105+ async def put_callback (value : T ):
106+ await sender .put (controller , attribute , value )
107+ case _:
108+
109+ async def put_callback (value : T ):
110+ pass
99111
112+ return put_callback
100113
101- def _get_scan_tasks (mapping : Mapping ) -> list [Callable ]:
102- scan_dict : dict [float , list [Callable ]] = defaultdict (list )
114+
115+ def _get_scan_tasks (mapping : Mapping ) -> list [Callback ]:
116+ scan_dict : dict [float , list [Callback ]] = defaultdict (list )
103117
104118 for single_mapping in mapping .get_controller_mappings ():
105119 _add_scan_method_tasks (scan_dict , single_mapping )
@@ -110,16 +124,15 @@ def _get_scan_tasks(mapping: Mapping) -> list[Callable]:
110124
111125
112126def _add_scan_method_tasks (
113- scan_dict : dict [float , list [Callable ]], single_mapping : SingleMapping
127+ scan_dict : dict [float , list [Callback ]], single_mapping : SingleMapping
114128):
115- for method in single_mapping .scan_methods .values ():
116- scan_dict [method .period ].append (
117- MethodType (method .fn , single_mapping .controller )
118- )
129+ for scan in single_mapping .scan_methods .values ():
130+ scan_dict [scan .period ].append (scan )
119131
120132
121133def _add_attribute_updater_tasks (
122- scan_dict : dict [float , list [Callable ]], single_mapping : SingleMapping
134+ scan_dict : dict [float , list [Callback ]],
135+ single_mapping : SingleMapping ,
123136):
124137 for attribute in single_mapping .attributes .values ():
125138 match attribute :
@@ -128,12 +141,20 @@ def _add_attribute_updater_tasks(
128141 attribute , single_mapping .controller
129142 )
130143 scan_dict [update_period ].append (callback )
144+ case _:
145+ pass
131146
132147
133- def _create_updater_callback (attribute , controller ):
148+ def _create_updater_callback (
149+ attribute : AttrR [T ], controller : BaseController
150+ ) -> Callback :
134151 async def callback ():
135152 try :
136- await attribute .updater .update (controller , attribute )
153+ match attribute .updater :
154+ case Updater () as updater :
155+ await updater .update (controller , attribute )
156+ case _:
157+ pass
137158 except Exception as e :
138159 print (
139160 f"Update loop in { attribute .updater } stopped:\n "
@@ -144,15 +165,15 @@ async def callback():
144165 return callback
145166
146167
147- def _get_periodic_scan_tasks (scan_dict : dict [float , list [Callable ]]) -> list [Callable ]:
148- periodic_scan_tasks : list [Callable ] = []
168+ def _get_periodic_scan_tasks (scan_dict : dict [float , list [Callback ]]) -> list [Callback ]:
169+ periodic_scan_tasks : list [Callback ] = []
149170 for period , methods in scan_dict .items ():
150171 periodic_scan_tasks .append (_create_periodic_scan_task (period , methods ))
151172
152173 return periodic_scan_tasks
153174
154175
155- def _create_periodic_scan_task (period , methods : list [Callable ]) -> Callable :
176+ def _create_periodic_scan_task (period : float , methods : list [Callback ]) -> Callback :
156177 async def scan_task () -> None :
157178 while True :
158179 await asyncio .gather (* [method () for method in methods ])
0 commit comments