Coverage for src\zapy\templating\eval.py: 84%

1 import ast

2

3 from .traceback import annotate_traceback

4

5

6 _python_code = """

7 async def __exec_wrapper(_globs):

8 globals().update(**_globs)

9 __placeholder

10 return locals()

11"""

12

13 async def exec_async(custom_code: str, _globals: dict):

14 parsed_ast = ast.parse(_python_code)

15 is_placeholder = lambda node: isinstance(node, ast.Expr) and \

16 isinstance(node.value, ast.Name) and \

17 node.value.id == "__placeholder"

18

19 for node in ast.walk(parsed_ast):

20 if is_placeholder(node):

21 custom_ast = ast.parse(custom_code)

22 new_node = custom_ast

23 node.value = new_node

24

25 unparsed = ast.unparse(parsed_ast)

26 exec(unparsed)

27

28 try:

29 func = locals()['__exec_wrapper']

30 new_locals = await func(_globals)

31 except BaseException as e:

32 annotate_traceback(e, unparsed, location='exec_async')

33 raise

34

35 _globals.update(new_locals)

36

37

38 def sync_exec(custom_code: str, _globals: dict):

39 try:

40 return exec(custom_code, _globals)

41 except BaseException as e:

42 annotate_traceback(e, custom_code, location='sync_exec')

43 raise

44

45 def sync_eval(custom_code: str, _globals: dict):

46 try:

47 return eval(custom_code, _globals)

48 except BaseException as e:

49 annotate_traceback(e, custom_code, location='sync_eval')

50 raise