@@ -188,6 +188,10 @@ def __getattr__(self, attr):
188188 raise NameError (f"name '{ self .name } ' is not defined" )
189189 return getattr (self .value , attr )
190190
191+ def __repr__ (self ):
192+ """Generate string with address and value."""
193+ return f"EvalLocalVar @{ hex (id (self ))} = { self .value if self .defined else 'undefined' } "
194+
191195
192196class EvalName :
193197 """Identifier that hasn't yet been resolved."""
@@ -350,7 +354,7 @@ async def pyscript_service_handler(call):
350354 func_args .update (call .data )
351355
352356 async def do_service_call (func , ast_ctx , data ):
353- await func .call (ast_ctx , [], call .data )
357+ await func .call (ast_ctx , ** call .data )
354358 if ast_ctx .get_exception_obj ():
355359 ast_ctx .get_logger ().error (ast_ctx .get_exception_long ())
356360
@@ -575,7 +579,7 @@ async def try_aeval(self, ast_ctx, arg):
575579 if ast_ctx .exception_long is None :
576580 ast_ctx .exception_long = ast_ctx .format_exc (err , arg .lineno , arg .col_offset )
577581
578- async def call (self , ast_ctx , args = None , kwargs = None ):
582+ async def call (self , ast_ctx , * args , ** kwargs ):
579583 """Call the function with the given context and arguments."""
580584 sym_table = {}
581585 if args is None :
@@ -668,6 +672,19 @@ def __del__(self):
668672 self .func .trigger_stop ()
669673
670674
675+ class EvalFuncVarClassInst (EvalFuncVar ):
676+ """Class for a callable pyscript class instance function."""
677+
678+ def __init__ (self , func , class_inst ):
679+ """Initialize instance with given EvalFunc function."""
680+ super ().__init__ (func )
681+ self .class_inst = class_inst
682+
683+ def call (self , ctx , * args , ** kwargs ):
684+ """Call the EvalFunc function."""
685+ return self .func .call (ctx , self .class_inst , * args , ** kwargs )
686+
687+
671688class AstEval :
672689 """Python interpreter AST object evaluator."""
673690
@@ -858,19 +875,7 @@ async def ast_classdef(self, arg):
858875 raise SyntaxError (f"{ val .name ()} statement outside loop" )
859876 self .sym_table = self .sym_table_stack .pop ()
860877
861- for name , func in sym_table .items ():
862- if not isinstance (func , EvalFuncVar ):
863- continue
864-
865- def class_func_factory (func ):
866- async def class_func_wrapper (this_self , * args , ** kwargs ):
867- method_args = [this_self , * args ]
868- return await func .call (self , method_args , kwargs )
869-
870- return class_func_wrapper
871-
872- sym_table [name ] = class_func_factory (func .get_func ())
873-
878+ sym_table ["__init__evalfunc_wrap__" ] = None
874879 if "__init__" in sym_table :
875880 sym_table ["__init__evalfunc_wrap__" ] = sym_table ["__init__" ]
876881 del sym_table ["__init__" ]
@@ -1017,7 +1022,7 @@ async def ast_with(self, arg, async_attr=""):
10171022 )
10181023 for ctx in ctx_list :
10191024 if ctx ["target" ]:
1020- value = await self .call_func (ctx ["enter" ], enter_attr , [ ctx ["manager" ]], {} )
1025+ value = await self .call_func (ctx ["enter" ], enter_attr , ctx ["manager" ])
10211026 await self .recurse_assign (ctx ["target" ], value )
10221027 for arg1 in arg .body :
10231028 val = await self .aeval (arg1 )
@@ -1027,14 +1032,14 @@ async def ast_with(self, arg, async_attr=""):
10271032 hit_except = True
10281033 exit_ok = True
10291034 for ctx in reversed (ctx_list ):
1030- ret = await self .call_func (ctx ["exit" ], exit_attr , [ ctx ["manager" ], * sys .exc_info ()], {} )
1035+ ret = await self .call_func (ctx ["exit" ], exit_attr , ctx ["manager" ], * sys .exc_info ())
10311036 exit_ok = exit_ok and ret
10321037 if not exit_ok :
10331038 raise
10341039 finally :
10351040 if not hit_except :
10361041 for ctx in reversed (ctx_list ):
1037- await self .call_func (ctx ["exit" ], exit_attr , [ ctx ["manager" ], None , None , None ], {} )
1042+ await self .call_func (ctx ["exit" ], exit_attr , ctx ["manager" ], None , None , None )
10381043 return val
10391044
10401045 async def ast_asyncwith (self , arg ):
@@ -1590,19 +1595,24 @@ async def ast_call(self, arg):
15901595 func_name = func .get_name ()
15911596 func = func .get ()
15921597 _LOGGER .debug ("%s: calling %s(%s, %s)" , self .name , func_name , arg_str , kwargs )
1593- return await self .call_func (func , func_name , args , kwargs )
1598+ return await self .call_func (func , func_name , * args , ** kwargs )
15941599
1595- async def call_func (self , func , func_name , args , kwargs ):
1600+ async def call_func (self , func , func_name , * args , ** kwargs ):
15961601 """Call a function with the given arguments."""
15971602 if isinstance (func , EvalFuncVar ):
1598- return await func .get_func (). call (self , args , kwargs )
1603+ return await func .call (self , * args , ** kwargs )
15991604 if inspect .isclass (func ) and hasattr (func , "__init__evalfunc_wrap__" ):
1600- #
1601- # since our __init__ function is async, create the class instance
1602- # without arguments and then call the async __init__evalfunc_wrap__
1603- #
16041605 inst = func ()
1605- await inst .__init__evalfunc_wrap__ (* args , ** kwargs )
1606+ for name in inst .__dir__ ():
1607+ value = getattr (inst , name )
1608+ if type (value ) is not EvalFuncVar :
1609+ continue
1610+ setattr (inst , name , EvalFuncVarClassInst (value .get_func (), inst ))
1611+ if getattr (func , "__init__evalfunc_wrap__" ) is not None :
1612+ #
1613+ # since our __init__ function is async, call the renamed one
1614+ #
1615+ await inst .__init__evalfunc_wrap__ .call (self , * args , ** kwargs )
16061616 return inst
16071617 if asyncio .iscoroutinefunction (func ):
16081618 return await func (* args , ** kwargs )
0 commit comments