def test_eval_assignment(): ctx = Context() # Do not allow assigning to non-trivial expressions ast, _ = exp.parse('(1+1*x)*9') with raises(Exception): ast.value = 10 # Do not allow assigning to built-in constants ast, _ = exp.parse('True') with raises(Exception): ast.value = 10 # Do not allow assigning to function calls ast, _ = exp.parse('f(1)') with raises(Exception): ast.value = 10 # Do not allow assigning to constant lists ast, _ = exp.parse("[1,2,3,4]") with raises(Exception): ast.value = 10 # Do not allow assigning to constants ast, _ = exp.parse("'ahoj'") with raises(Exception): ast.value = 10 # Allow assigning to non-existing variables ast, _ = exp.parse('x') ast.bind_ctx(ctx) ast.value = 10 assert ctx.x == 10 # Allow assigning to existing variables ast.value = 20 assert ctx.x == 20 # Allow assigning to list elements ctx.lst = [1, 2, 3] ctx.x = 0 ast, _ = exp.parse("lst[x]") ast.bind_ctx(ctx) ast.value = 20 assert ctx.lst[0] == 20 # Allow assigning to non-existing object attributes ctx.obj = Context() ast, _ = exp.parse('obj.test') ast.bind_ctx(ctx) ast.value = 30987 assert ctx.obj.test == 30987 # Allow assigning to existing object attributes ast.value = 40 assert ctx.obj.test == 40
def test_parse(): ctx = Context() # Test Simple Arithmetic Expressions ast, _ = exp.parse('(1+1*8)*9') assert ast.evalctx(ctx) is 81 # Test Simple Arithmetic Expressions ast, _ = exp.parse('(1-1)') assert ast.evalctx(ctx) is 0 # Test Simple Arithmetic Expressions ast, _ = exp.parse('(-1)') assert ast.evalctx(ctx) is -1 # Test Boolean Expressions ast, _ = exp.parse('True and False') assert ast.evalctx(ctx) is False ast, _ = exp.parse('True and not False') assert ast.evalctx(ctx) is True # Test is ast, _ = exp.parse("1 is None") assert ast.evalctx(ctx) is False ast, _ = exp.parse("None is None") assert ast.evalctx(ctx) is True ast, _ = exp.parse("False is not None") assert ast.evalctx(ctx) is True # Test Slices ctx.s = "abcde" ast, _ = exp.parse('s[-1]') assert ast.evalctx(ctx) == 'e' ast, _ = exp.parse('s[0]') assert ast.evalctx(ctx) == 'a' ast, _ = exp.parse('s[1:3]') assert ast.evalctx(ctx) == 'bc' ast, _ = exp.parse('s[0:-1:2]') assert ast.evalctx(ctx) == 'ac' ast, _ = exp.parse('s[1:]') assert ast.evalctx(ctx) == 'bcde' ast, _ = exp.parse('s[:-1]') assert ast.evalctx(ctx) == 'abcd' # Test Lists ast, _ = exp.parse('[1,2,3,4]') assert ast.evalctx(ctx) == [1, 2, 3, 4] # Test Comprehension ast, _ = exp.parse('[p+1 for p in [1,2,3,4]]') assert ast.evalctx(ctx) == [2, 3, 4, 5] ast, _ = exp.parse('[p+1 for p in [1,2,3,4] if p%2==0]') assert ast.evalctx(ctx) == [3, 5] # Test Builtins ast, _ = exp.parse("str(10)") assert ast.evalctx(ctx) == "10" ast, _ = exp.parse("int('21')") assert ast.evalctx(ctx) == 21 ast, _ = exp.parse("len([1,2,3])") assert ast.evalctx(ctx) == 3 ctx.str = lambda x: "str(" + str(x) + ")" ast, _ = exp.parse("str(10)") assert str(ast) == "str(10)" del ctx.str # Test Object Access ctx.obj = Context() ctx.obj.a = 10 ctx.obj.b = Context() ctx.obj.b.c = 20 ctx.obj.d = [Context({'a': 30})] ast, _ = exp.parse('obj.a') assert ast.evalctx(ctx) == 10 ast, _ = exp.parse('obj.b.c') assert ast.evalctx(ctx) == 20 ast, _ = exp.parse('obj.d[0].a') assert ast.evalctx(ctx) == 30 # Test Array Access ast, _ = exp.parse('mylst[0][1][2]') ctx.mylst = [[None, [None, None, "Ahoj"]]] assert ast.evalctx(ctx) == "Ahoj" # Test String slices ast, _ = exp.parse('"ahoj"[1:]') assert ast.evalctx(ctx) == "hoj" ast, _ = exp.parse('"ahoj"[:1]') assert ast.evalctx(ctx) == "a" ast, _ = exp.parse('"ahoj"[-1]') assert ast.evalctx(ctx) == "j" # Test array concatenation ast, _ = exp.parse('([0]+["mixin"])[1]') assert ast.evalctx(ctx) == "mixin" # Test Function Calls ast, _ = exp.parse('"a,b,c,d".split(",")') assert ast.evalctx(ctx) == ['a', 'b', 'c', 'd'] ctx.func = lambda x, ev: str(x + 10) + ev ctx.ch = 20 ctx.s = 'Hi' ast, _ = exp.parse("func(ch,ev=s)") ast.bind_ctx(ctx) ctx.s = 'Hello' assert ast.eval() == '30Hello' assert ast.evalctx(ctx) == '30Hello' # Test Complex Expressions expr = '(1+2*obj.a - 10)' ast, _ = exp.parse(expr) assert ast.evalctx(ctx) == 11 expr = '[(1+2*a[1+3] - 10) for a in [[2,1,2,3,4,5],[1,2],[2,2,2,2,2,2,2]] if a[0] % 2 == 0]' ast, _ = exp.parse(expr) assert ast.evalctx(ctx) == [-1, -5] # Test parse cache for i in range(10): expr = '[(1+2*a[1+3] - 10) for a in [[2,1,2,3,4,5],[1,2],[2,2,2,2,2,2,2]] if a[0] % 2 == 0]' ast, _ = exp.parse(expr) assert ast.evalctx(ctx) == [-1, -5]