11from asyncio import iscoroutinefunction
22from collections .abc import Callable , Coroutine
33from inspect import Signature , getdoc , signature
4+ from types import MethodType
45from typing import Any , Generic , TypeVar
56
67from fastcs .controller import BaseController
1314CommandCallback = Callable [[ControllerType ], Coroutine [None , None , None ]]
1415ScanCallback = Callable [[ControllerType ], Coroutine [None , None , None ]]
1516PutCallback = Callable [[ControllerType , Any ], Coroutine [None , None , None ]]
17+ BoundCommandCallback = Callable [[], Coroutine [None , None , None ]]
18+ BoundScanCallback = Callable [[], Coroutine [None , None , None ]]
19+ BoundPutCallback = Callable [[Any ], Coroutine [None , None , None ]]
20+
21+
22+ method_not_bound_error = NotImplementedError (
23+ "Method must be bound to a controller instance to be callable"
24+ )
1625
1726
1827class Method (Generic [ControllerType ]):
@@ -62,15 +71,21 @@ def __init__(self, fn: ScanCallback[ControllerType], period: float) -> None:
6271
6372 self ._period = period
6473
74+ @property
75+ def period (self ):
76+ return self ._period
77+
6578 def _validate (self , fn : ScanCallback [ControllerType ]) -> None :
6679 super ()._validate (fn )
6780
6881 if not len (self .parameters ) == 1 :
6982 raise FastCSException ("Scan method cannot have arguments" )
7083
71- @property
72- def period (self ):
73- return self ._period
84+ def bind (self , controller : ControllerType ) -> "BoundScan" :
85+ return BoundScan (MethodType (self .fn , controller ), self ._period )
86+
87+ def __call__ (self ):
88+ raise method_not_bound_error
7489
7590
7691class Put (Method [ControllerType ]):
@@ -83,6 +98,12 @@ def _validate(self, fn: PutCallback[ControllerType]) -> None:
8398 if not len (self .parameters ) == 2 :
8499 raise FastCSException ("Put method can only take one argument" )
85100
101+ def bind (self , controller : ControllerType ) -> "BoundPut" :
102+ return BoundPut (MethodType (self .fn , controller ))
103+
104+ def __call__ (self , value : Any ):
105+ raise method_not_bound_error
106+
86107
87108class Command (Method [ControllerType ]):
88109 def __init__ (
@@ -96,32 +117,56 @@ def _validate(self, fn: CommandCallback[ControllerType]) -> None:
96117 if not len (self .parameters ) == 1 :
97118 raise FastCSException ("Command method cannot have arguments" )
98119
120+ def bind (self , controller : ControllerType ) -> "BoundCommand" :
121+ return BoundCommand (MethodType (self .fn , controller ))
99122
100- class BoundScan (Scan ):
101- def __init__ (self , scan : Scan [BaseController ], controller : BaseController ) -> None :
102- super ().__init__ (scan .fn , scan .period )
123+ def __call__ (self ):
124+ raise method_not_bound_error
103125
104- self ._controller = controller
105126
106- async def __call__ (self ):
107- return await self ._fn (self ._controller )
127+ class BoundScan (Method [BaseController ]):
128+ def __init__ (self , fn : BoundScanCallback , period : float ):
129+ super ().__init__ (fn )
108130
131+ self ._period = period
109132
110- class BoundPut ( Put ):
111- def __init__ (self , put : Put , controller : BaseController ) -> None :
112- super (). __init__ ( put . fn )
133+ @ property
134+ def period (self ) :
135+ return self . _period
113136
114- self ._controller = controller
137+ def _validate (self , fn : BoundScanCallback ) -> None :
138+ super ()._validate (fn )
139+
140+ if not len (self .parameters ) == 0 :
141+ raise FastCSException ("Scan method cannot have arguments" )
142+
143+ def __call__ (self ):
144+ return self ._fn ()
145+
146+
147+ class BoundPut (Method [BaseController ]):
148+ def __init__ (self , fn : BoundPutCallback ):
149+ super ().__init__ (fn )
150+
151+ def _validate (self , fn : BoundPutCallback ) -> None :
152+ super ()._validate (fn )
153+
154+ if not len (self .parameters ) == 1 :
155+ raise FastCSException ("Put method can only take one argument" )
115156
116- async def __call__ (self , value : bool | int | float | str ):
117- return await self ._fn (self . _controller , value )
157+ def __call__ (self , value : Any ):
158+ return self ._fn (value )
118159
119160
120- class BoundCommand (Command ):
121- def __init__ (self , command : Command , controller : BaseController ) -> None :
122- super ().__init__ (command .fn )
161+ class BoundCommand (Method [BaseController ]):
162+ def __init__ (self , fn : BoundCommandCallback ):
163+ super ().__init__ (fn )
164+
165+ def _validate (self , fn : BoundCommandCallback ) -> None :
166+ super ()._validate (fn )
123167
124- self ._controller = controller
168+ if not len (self .parameters ) == 0 :
169+ raise FastCSException ("Command method cannot have arguments" )
125170
126- async def __call__ (self ):
127- return await self ._fn (self . _controller )
171+ def __call__ (self ):
172+ return self ._fn ()
0 commit comments