@@ -188,6 +188,10 @@ def __getattr__(self, attr):
188
188
raise NameError (f"name '{ self .name } ' is not defined" )
189
189
return getattr (self .value , attr )
190
190
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
+
191
195
192
196
class EvalName :
193
197
"""Identifier that hasn't yet been resolved."""
@@ -350,7 +354,7 @@ async def pyscript_service_handler(call):
350
354
func_args .update (call .data )
351
355
352
356
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 )
354
358
if ast_ctx .get_exception_obj ():
355
359
ast_ctx .get_logger ().error (ast_ctx .get_exception_long ())
356
360
@@ -575,7 +579,7 @@ async def try_aeval(self, ast_ctx, arg):
575
579
if ast_ctx .exception_long is None :
576
580
ast_ctx .exception_long = ast_ctx .format_exc (err , arg .lineno , arg .col_offset )
577
581
578
- async def call (self , ast_ctx , args = None , kwargs = None ):
582
+ async def call (self , ast_ctx , * args , ** kwargs ):
579
583
"""Call the function with the given context and arguments."""
580
584
sym_table = {}
581
585
if args is None :
@@ -668,6 +672,19 @@ def __del__(self):
668
672
self .func .trigger_stop ()
669
673
670
674
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
+
671
688
class AstEval :
672
689
"""Python interpreter AST object evaluator."""
673
690
@@ -858,19 +875,7 @@ async def ast_classdef(self, arg):
858
875
raise SyntaxError (f"{ val .name ()} statement outside loop" )
859
876
self .sym_table = self .sym_table_stack .pop ()
860
877
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
874
879
if "__init__" in sym_table :
875
880
sym_table ["__init__evalfunc_wrap__" ] = sym_table ["__init__" ]
876
881
del sym_table ["__init__" ]
@@ -1017,7 +1022,7 @@ async def ast_with(self, arg, async_attr=""):
1017
1022
)
1018
1023
for ctx in ctx_list :
1019
1024
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" ])
1021
1026
await self .recurse_assign (ctx ["target" ], value )
1022
1027
for arg1 in arg .body :
1023
1028
val = await self .aeval (arg1 )
@@ -1027,14 +1032,14 @@ async def ast_with(self, arg, async_attr=""):
1027
1032
hit_except = True
1028
1033
exit_ok = True
1029
1034
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 ())
1031
1036
exit_ok = exit_ok and ret
1032
1037
if not exit_ok :
1033
1038
raise
1034
1039
finally :
1035
1040
if not hit_except :
1036
1041
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 )
1038
1043
return val
1039
1044
1040
1045
async def ast_asyncwith (self , arg ):
@@ -1590,19 +1595,24 @@ async def ast_call(self, arg):
1590
1595
func_name = func .get_name ()
1591
1596
func = func .get ()
1592
1597
_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 )
1594
1599
1595
- async def call_func (self , func , func_name , args , kwargs ):
1600
+ async def call_func (self , func , func_name , * args , ** kwargs ):
1596
1601
"""Call a function with the given arguments."""
1597
1602
if isinstance (func , EvalFuncVar ):
1598
- return await func .get_func (). call (self , args , kwargs )
1603
+ return await func .call (self , * args , ** kwargs )
1599
1604
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
- #
1604
1605
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 )
1606
1616
return inst
1607
1617
if asyncio .iscoroutinefunction (func ):
1608
1618
return await func (* args , ** kwargs )
0 commit comments