Example #1
0
def test_model_plugin():
    div_elem = MockElement('div', id='test')
    text_elem = MockElement('#text', id='text')
    text_elem.text = "{{ c['name'] }}"
    div_elem <= text_elem
    input_elem = MockElement('input', model='c["name"]', id='input')
    div_elem <= input_elem
    document <= div_elem
    tpl = Template(document['test'])
    ctx = Context({})
    ctx.c = {'name': ''}
    elem = tpl.bind_ctx(ctx)
    text_elem = document['text']
    input_elem = document['input']
    assert text_elem.text == ''
    input_elem.setAttribute('value', 'Jonathan')
    assert text_elem.text == 'Jonathan'
    assert ctx.c['name'] == 'Jonathan'
    assert input_elem.value == 'Jonathan'
    input_elem.value = 'Test'
    assert text_elem.text == 'Jonathan'
    assert ctx.c['name'] == 'Jonathan'
    ctx.c['name'] = 'Test2'
    assert input_elem.value == 'Test2'
    assert text_elem.text == 'Test2'
Example #2
0
def test_nested_for():
    # Test nested loops
    doc = MockElement('div')
    div_elem = MockElement('div')
    div_elem.attributes.append(MockAttr('for', 'c in colours'))
    div_elem.attributes.append(MockAttr('style', '{{ c["css"] }}'))
    ch_elem = MockElement('span', id='id-{{name}}')
    ch_elem.attributes.append(MockAttr('for', 'name in c["names"]'))
    t_elem = MockElement('#text')
    t_elem.text = "{{ name }}{{parent_attr}}"
    ch_elem <= t_elem
    div_elem <= ch_elem
    doc <= div_elem
    plug = _compile(doc)
    ctx = Context()
    ctx.parent_attr = "Test"
    ctx.colours = [{
        'names': ['Red', 'Reddish'],
        'css': 'red'
    }, {
        'names': ['Blue'],
        'css': 'blue'
    }]
    doc = plug.bind_ctx(ctx)
    nocomment_children = filter_comments(doc.children)
    assert len(nocomment_children) == 2
    assert len(filter_comments(nocomment_children[0].children)) == 2
    red_elem = doc._findChild('id-Red')
    assert red_elem.children[0].text == 'RedTest'
Example #3
0
def test_for_plugin():
    div_elem = MockElement('div', style='{{ c["css"] }}')
    text_elem = MockElement('#text')
    text_elem.text = "{{ c['name'] }}"
    div_elem <= text_elem

    plug = For(div_elem, loop_spec="c in colours")
    ctx = Context({})
    elems = plug.bind_ctx(ctx)
    assert filter_comments(elems) == []
    ctx.colours = [{
        'name': 'Red',
        'css': 'red'
    }, {
        'name': 'Blue',
        'css': 'blue'
    }]
    assert plug._dirty_self is True
    elems = plug.update()
    nocomment = filter_comments(elems)
    assert len(nocomment) == 2
    assert hasattr(nocomment[0].attributes, 'style')
    assert nocomment[0].attributes.style == "red"
    assert nocomment[0].children[0].text == "Red"
    assert nocomment[1].attributes.style == "blue"
    assert nocomment[1].children[0].text == "Blue"
    ctx.colours[0]['name'] = 'Reddish'
    assert plug._dirty_self is False
    assert plug._dirty_subtree is True
    assert plug.update() is None
    assert filter_comments(nocomment[0].children)[0].text == "Reddish"
Example #4
0
def test_future(event_loop):
    asyncio.set_event_loop(event_loop)
    ctx = Context()
    fut = asyncio. async (asyncio.sleep(0.1, result=3))
    ctx.test = fut
    assert hasattr(ctx, 'test') is False
    event_loop.run_until_complete(fut)
    assert ctx.test == 3
Example #5
0
 def test_clone(self):
     self.prepare("x**2 + x")
     clone = self.obs.clone()
     ctx = Context()
     ctx.x = 0
     clone.bind_ctx(ctx)
     self.ctx.x = 1
     assert clone.value == 0
     assert self.obs.value == 2
Example #6
0
def test_incomplete():
    ctx = Context()
    s = InterpolatedStr("Ahoj {{ name }} {{ surname }}!")
    assert s.value == "Ahoj  !"

    ctx.name = "Jonathan"
    s.bind_ctx(ctx)
    assert s.value == "Ahoj Jonathan !"

    ctx.surname = "Verner"
    assert s.value == "Ahoj Jonathan Verner!"
Example #7
0
def test_string_interp():
    ctx = Context()
    ctx.name = "James"
    s = InterpolatedStr("My name is {{ surname }}, {{name}} {{ surname}}.")
    s.bind_ctx(ctx)
    t = TObserver(s)
    assert s.value == "My name is , James ."

    ctx.surname = "Bond"
    data = t.events.pop().data
    assert s.value == "My name is Bond, James Bond."

    # Should correctly interpolate two immediately succeeding expressions
    ctx.sur = "B"
    s = InterpolatedStr('{{name}}{{sur}}')
    s.bind_ctx(ctx)
    assert s.value == "JamesB"
Example #8
0
def test_text_plugin():
    text_elem = MockElement('#text')
    text_elem.text = "Hello {{ name }}"
    tp = TextPlugin(text_elem)
    c = Context({})
    elem = tp.bind_ctx(c)
    assert elem.text == "Hello "
    c.name = "Jonathan"
    assert tp._dirty_self is True
    assert tp.update() is None
    assert tp._dirty_self is False
    assert elem.text == "Hello Jonathan"

    tp2 = tp.clone()
    c2 = Context({'name':'Ansa'})
    elem2 = tp2.bind_ctx(c2)
    assert elem2.text == "Hello Ansa"
    assert elem.text == "Hello Jonathan"
    assert tp._dirty_self is False

    text_elem = MockElement('#text')
    text_elem.text = "Hello"
    tp = _compile(text_elem)
    c = Context({})
    elem = tp.bind_ctx(c)
    assert elem.text == "Hello"
    c.name = "Jonathan"
    assert tp.update() is None
    assert elem.text == "Hello"
Example #9
0
 def setAttribute(self, name, value):
     if name == 'value':
         self.value = value
         self.emit('input', Context({'target': self}))
     else:
         pos = self._indexAttr(name)
         if pos > -1:
             self.attributes[pos].value = value
         else:
             self.attributes.append(MockAttr(name, value))
Example #10
0
def test_parse_interpolated_string():
    ctx = Context()
    ctx.name = 'Name'

    asts = exp.parse_interpolated_str(
        'Test text {{ 1+3 }} other text {{ "ahoj" }} final text.')
    val = "".join([ast.evalctx(ctx) for ast in asts])
    assert val == 'Test text 4 other text ahoj final text.'

    asts = exp.parse_interpolated_str(
        'Test text {{ 1+3 }} other text {{ name }} final text.')
    val = "".join([ast.evalctx(ctx) for ast in asts])
    assert val == 'Test text 4 other text Name final text.'

    asts = exp.parse_interpolated_str(
        'Test text {{ 1+3 }} other text {{ len(name) }} final text.')
    val = "".join([ast.evalctx(ctx) for ast in asts])
    assert val == 'Test text 4 other text 4 final text.'

    asts = exp.parse_interpolated_str(
        'Test text {{ "{{{{}}{}{}}}" }} other }}')
    val = "".join([ast.evalctx(ctx) for ast in asts])
    assert val == 'Test text {{{{}}{}{}}} other }}'
Example #11
0
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
Example #12
0
def test_extension():
    base = Context()
    base.a = 10
    base.c = 30

    child = Context(base=base)

    # Child should have access to parent
    assert child.a == 10

    # The _get method should work for accessing parent
    assert child._get('a') == 10

    # Child should not be allowed to modify parent
    child.a = 20
    assert child.a == 20
    assert base.a == 10

    # Attributes should propagate recursively
    second_child = Context(base=child)
    assert second_child.c == 30
    assert second_child.a == 20
Example #13
0
def test_interpolated_attrs_plugin():
    text_elem = MockElement('#text')
    text_elem.text = "{{ name }}"
    t2_elem = MockElement('#text')
    t2_elem.text = "ahoj"
    div_elem = MockElement('div', id="test")
    div_elem <= text_elem
    div_elem <= t2_elem

    plug = InterpolatedAttrsPlugin(div_elem)
    ctx = Context({})
    elem = plug.bind_ctx(ctx)
    assert elem.attributes.id == "test"

    div_elem.setAttribute('id', "{{ id }}")
    plug = InterpolatedAttrsPlugin(div_elem)
    ctx = Context({})
    elem = plug.bind_ctx(ctx)
    text_elem = elem.children[0]
    com_elem = elem.children[1]
    t2_elem = elem.children[2]
    assert elem.attributes.id == ""
    assert com_elem.tagName == 'comment'
    assert text_elem.text == ""
    assert t2_elem.text == "ahoj"
    assert plug._dirty_self is False
    assert plug._dirty_subtree is False
    ctx.id = "test_id"
    assert plug._dirty_self is True
    assert plug._dirty_subtree is False
    assert plug.update() is None
    assert elem.attributes.id == "test_id"
    ctx.name = "Jonathan"
    assert plug._dirty_self is False
    assert plug._dirty_subtree is True
    assert plug.update() is None
    assert text_elem.text == "Jonathan"
    assert plug._dirty_subtree is False

    div_elem.attributes.append(MockAttr('id', '{{ id }}'))
    plug = _compile(div_elem)
    ctx = Context({})
    elem = plug.bind_ctx(ctx)
    assert elem.attributes.id == ""
    ctx.id = "test_id"
    assert plug.update() is None
    assert elem.attributes.id == "test_id"

    div_elem.attributes.extend([
        MockAttr('id', '{{ id }}'),
        MockAttr('style', '{{ css }}'),
        MockAttr('name', '???')
    ])
    plug = _compile(div_elem)
    ctx = Context({})
    elem = plug.bind_ctx(ctx)
    assert elem.attributes.id == ""
    assert elem.attributes.style == ""
    assert elem.attributes.name == "???"
    ctx.css = "border:1px;"
    assert plug.update() is None
    assert elem.attributes.style == "border:1px;"
Example #14
0
 def setup_method(self, method):
     self.called = False
     self.ctx = Context()
     document._reset()
Example #15
0
 def setup_method(self, method):
     self.ctx = Context()
     self.ctx._clear()
Example #16
0
class TestExpressionChanges(object):
    def setup_method(self, method):
        self.ctx = Context()
        self.ctx._clear()

    def prepare(self, expr):
        self.obs, _ = exp.parse(expr)
        self.obs.bind_ctx(self.ctx)
        try:
            self.obs.eval()
        except:
            pass
        self.t = TObserver(self.obs)

    def exec_test(self, new):
        data = self.t.events.pop().data

        if new is not None:
            assert self.obs.value == new
        else:
            assert self.obs.cache_status is False
            try:
                self.obs.eval()
            except:
                pass
            assert self.obs.defined is False
            assert 'value' not in data

    def test_clone(self):
        self.prepare("x**2 + x")
        clone = self.obs.clone()
        ctx = Context()
        ctx.x = 0
        clone.bind_ctx(ctx)
        self.ctx.x = 1
        assert clone.value == 0
        assert self.obs.value == 2

    def test_arithmetic_exp(self):
        self.ctx.a = 1
        self.ctx.b = -2
        self.ctx.c = 0.5

        self.prepare("a*x**2 + b*x + c*x")
        assert self.obs.cache_status is False
        assert self.obs.defined is False

        self.ctx.d = 10
        assert len(self.t.events) == 0

        self.ctx.x = 0
        self.exec_test(0)

        self.ctx.x = 1
        self.exec_test(-0.5)

    def test_comprehension(self):
        self.ctx.lst = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
        self.prepare("[p+1 for p in lst if p%2 == 0]")
        assert self.obs.cache_status is True

        self.ctx.lst.append(4)
        assert self.obs.cache_status is False
        self.exec_test([-3, -1, 1, 3, 5, 5])

        self.ctx.lst.remove(4)
        self.exec_test([-3, -1, 1, 3, 5])

        self.ctx.lst.clear()
        self.exec_test([])

    def test_attr_acces(self):
        self.ctx.root = MockObject(depth=3)
        self.prepare("root.child.child.child.leaf and True")
        assert self.obs.value is True
        assert self.obs.cache_status is True

        self.ctx.root.child.child.child.leaf = False
        assert self.obs.cache_status is False
        self.exec_test(False)

        self.ctx.root.child = None
        self.exec_test(None)

    def test_func(self):
        self.ctx.func = lambda x, y: x + y
        self.prepare("func(a,b)")
        assert self.obs.cache_status is False

        self.ctx.a = 10
        assert self.obs.cache_status is False

        self.ctx.b = 20
        assert self.obs.cache_status is False
        self.exec_test(30)

        self.ctx.b = 30
        self.exec_test(40)

        self.ctx.func = lambda x, y: x * y
        self.exec_test(300)

        del self.ctx.a
        self.exec_test(None)

    def test_array_index(self):
        self.ctx.lst = [[1, 2, 3], 2, 3, 4, 5]
        self.ctx.a = 0
        self.prepare("lst[0][a]")
        assert self.obs.cache_status is True
        assert self.obs.value == 1

        self.ctx.lst[1] = 2
        self.exec_test(1)
        self.ctx.a = 2
        self.exec_test(3)
        self.ctx.a = 3
        self.exec_test(None)
        self.ctx.lst[0].append(4)
        self.exec_test(4)
        self.ctx.lst.pop()
        self.exec_test(4)
Example #17
0
 def setup_method(self, method):
     self.called = False
     self.ctx = Context()
Example #18
0
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]