diff --git a/mako/parsetree.py b/mako/parsetree.py index 04686ec..c1a52e7 100644 --- a/mako/parsetree.py +++ b/mako/parsetree.py @@ -322,7 +322,7 @@ def _parse_attributes(self, expressions, nonexpressions): for key in self.attributes: if key in expressions: expr = [] - for x in re.compile(r"(\${.+?})", re.S).split( + for x in re.compile(r"(\${.+})", re.S).split( self.attributes[key] ): m = re.compile(r"^\${(.+?)}$", re.S).match(x) diff --git a/test/test_lexer.py b/test/test_lexer.py index 66c0a1d..d83b9ec 100644 --- a/test/test_lexer.py +++ b/test/test_lexer.py @@ -810,6 +810,160 @@ def test_tricky_expression(self): ), ) + def test_dict_expression(self): + template = """ + <%def name="dtest(d)"> + % for k,v in d.items(): + ${k} = ${v} + % endfor + + + <%self:dtest d="${ + { + 'id':'4', + 'foo':'barr' + } + }" /> + """ + nodes = Lexer(template).parse() + self._compare( + nodes, + TemplateNode( + {}, + [ + Text('\n ', (1, 1)), + DefTag( + 'def', + {'name': 'dtest(d)'}, (2, 9), + [ + Text('\n', (2, 31)), + ControlLine('for', 'for k,v in d.items():', False, (3, 1)), + Text(' ', (4, 1)), + Expression('k', [], (4, 13)), + Text(' = ', (4, 17)), + Expression('v', [], (4, 20)), + Text('\n', (4, 24)), + ControlLine('for', 'endfor', True, (5, 1)), + Text(' ', (6, 1)) + ] + ), + Text('\n\n ', (6, 16)), + CallNamespaceTag('self:dtest', {'d': "${\n {\n 'id':'4',\n 'foo':'barr'\n }\n }"}, (8, 9), []), + Text('\n ', (13, 30)) + ] + ) + ) + + def test_dict_expression_2(self): + template = """ + <%def name="thing(thing)"> + ${type(thing)} + + + <%self:thing thing="foo" /> + + <%self:thing thing="${5}" /> + + <%self:thing thing="${[1,2,3]}" /> + + <%self:thing thing="${{'id':'4'}}" /> + + + <% + foo="this is foo" + g=False + %> + + <%def name="bar(x, y)"> + ${x} ${y} + + + <%self:bar x=" ${{'id':4}} " y="x${g and '1' or '2'}y"/> + + <%def name="dtest(d)"> + % for k,v in d.items(): + ${k} = ${v} + % endfor + % if 'embeded' in d and 'name' in d['embeded']: + ${d['embeded']['name']} + % endif + + + <%self:dtest d="${ { + 'x-on:click':'foo', + 'foo':'bar', + 'embeded':{'name':'J Doe'} + } }" /> + """ + nodes = Lexer(template).parse() + self._compare( + nodes, + TemplateNode( + {}, + [ + Text('\n ', (1, 1)), + DefTag( + 'def', + {'name': 'thing(thing)'}, + (2, 9), + [ + Text('\n ', (2, 35)), + Expression('type(thing)', [], (3, 13)), + Text('\n ', (3, 27)) + ] + ), + Text('\n\n ', (4, 16)), + CallNamespaceTag('self:thing', {'thing': 'foo'}, (6, 9), []), Text('\n\n ', (6, 36)), + CallNamespaceTag('self:thing', {'thing': '${5}'}, (8, 9), []), Text('\n\n ', (8, 37)), + CallNamespaceTag('self:thing', {'thing': '${[1,2,3]}'}, (10, 9), []), + Text('\n\n ', (10, 43)), + CallNamespaceTag('self:thing', {'thing': "${{'id':'4'}}"}, (12, 9), []), + Text('\n\n\n ', (12, 46)), + Code('\nfoo="this is foo"\ng=False\n \n', False, (15, 9)), + Text('\n\n ', (18, 11)), + DefTag( + 'def', + {'name': 'bar(x, y)'}, + (20, 9), + [ + Text('\n ', (20, 32)), + Expression('x', [], (21, 13)), + Text(' ', (21, 17)), + Expression('y', [], (21, 18)), + Text('\n ', (21, 22)) + ] + ), + Text('\n\n ', (22, 16)), + CallNamespaceTag('self:bar', {'x': " ${{'id':4}} ", 'y': "x${g and '1' or '2'}y"}, (24, 9), []), + Text('\n\n ', (24, 65)), + DefTag( + 'def', + {'name': 'dtest(d)'}, (26, 9), + [ + Text('\n', (26, 31)), + ControlLine('for', 'for k,v in d.items():', False, (27, 1)), + Text(' ', (28, 1)), + Expression('k', [], (28, 9)), + Text(' = ', (28, 13)), + Expression('v', [], (28, 16)), + Text('\n', (28, 20)), + ControlLine('for', 'endfor', True, (29, 1)), + ControlLine('if', "if 'embeded' in d and 'name' in d['embeded']:", False, (30, 1)), + Text(' ', (31, 1)), + Expression("d['embeded']['name']", [], (31, 9)), + Text('\n', (31, 32)), + ControlLine('if', 'endif', True, (32, 1)), + Text(' ', (33, 1)) + ] + ), + Text('\n\n ', + (33, 16)), + CallNamespaceTag('self:dtest', {'d': "${ {\n 'x-on:click':'foo',\n 'foo':'bar',\n 'embeded':{'name':'J Doe'}\n } }"}, (35, 9), []), + Text('\n ', (39, 16)) + ] + ) + ) + def test_tricky_code(self): template = """<% print('hi %>') %>""" nodes = Lexer(template).parse()