def test_basics(): for_loop = nodes.For( nodes.Name("foo", "store"), nodes.Name("seq", "load"), [nodes.Output([nodes.Name("foo", "load")])], [], None, False, ) tmpl = nodes.Template([ nodes.Assign(nodes.Name("foo", "store"), nodes.Name("bar", "load")), for_loop ]) sym = symbols_for_node(tmpl) assert sym.refs == { "foo": "l_0_foo", "bar": "l_0_bar", "seq": "l_0_seq", } assert sym.loads == { "l_0_foo": ("undefined", None), "l_0_bar": ("resolve", "bar"), "l_0_seq": ("resolve", "seq"), } sym = symbols_for_node(for_loop, sym) assert sym.refs == { "foo": "l_1_foo", } assert sym.loads == { "l_1_foo": ("param", None), }
def test_if_branching_multi_scope(): for_loop = nodes.For( nodes.Name("item", "store"), nodes.Name("seq", "load"), [ nodes.If( nodes.Name("expression", "load"), [nodes.Assign(nodes.Name("x", "store"), nodes.Const(42))], [], [], ), nodes.Include(nodes.Const("helper.html"), True, False), ], [], None, False, ) tmpl = nodes.Template( [nodes.Assign(nodes.Name("x", "store"), nodes.Const(23)), for_loop]) tmpl_sym = symbols_for_node(tmpl) for_sym = symbols_for_node(for_loop, tmpl_sym) assert for_sym.stores == set(["item", "x"]) assert for_sym.loads == { "l_1_x": ("alias", "l_0_x"), "l_1_item": ("param", None), "l_1_expression": ("resolve", "expression"), }
def test_basics(): for_loop = nodes.For( nodes.Name('foo', 'store'), nodes.Name('seq', 'load'), [nodes.Output([nodes.Name('foo', 'load')])], [], None, False) tmpl = nodes.Template([ nodes.Assign( nodes.Name('foo', 'store'), nodes.Name('bar', 'load')), for_loop]) sym = symbols_for_node(tmpl) assert sym.refs == { 'foo': 'l_0_foo', 'bar': 'l_0_bar', 'seq': 'l_0_seq', } assert sym.loads == { 'l_0_foo': ('undefined', None), 'l_0_bar': ('resolve', 'bar'), 'l_0_seq': ('resolve', 'seq'), } sym = symbols_for_node(for_loop, sym) assert sym.refs == { 'foo': 'l_1_foo', } assert sym.loads == { 'l_1_foo': ('param', None), }
def parse(self, parser): lineno = next(parser.stream).lineno index = nodes.Name("_", "store", lineno=lineno) how_many_times = parser.parse_expression() iterable = nodes.Call(nodes.Name("range", "load"), [how_many_times], [], None, None) parser.stream.expect("name:times") body = parser.parse_statements(["name:endrepeat"], drop_needle=True) return nodes.For(index, iterable, body, [], None, False, lineno=lineno)
def parse_for(self): """Parse a for loop.""" lineno = self.stream.expect('name:for').lineno target = self.parse_assign_target(extra_end_rules=('name:in',)) self.stream.expect('name:in') iter = self.parse_tuple(with_condexpr=False, extra_end_rules=('name:recursive',)) test = None if self.stream.skip_if('name:if'): test = self.parse_expression() recursive = self.stream.skip_if('name:recursive') body = self.parse_statements(('name:endfor', 'name:else')) if next(self.stream).value == 'endfor': else_ = [] else: else_ = self.parse_statements(('name:endfor',), drop_needle=True) return nodes.For(target, iter, body, else_, test, recursive, lineno=lineno)
def test_if_branching_multi_scope(): for_loop = nodes.For(nodes.Name('item', 'store'), nodes.Name('seq', 'load'), [ nodes.If(nodes.Name('expression', 'load'), [ nodes.Assign(nodes.Name('x', 'store'), nodes.Const(42))], []), nodes.Include(nodes.Const('helper.html'), True, False) ], [], None, False) tmpl = nodes.Template([ nodes.Assign(nodes.Name('x', 'store'), nodes.Const(23)), for_loop ]) tmpl_sym = symbols_for_node(tmpl) for_sym = symbols_for_node(for_loop, tmpl_sym) assert for_sym.stores == set(['item', 'x']) assert for_sym.loads == { 'l_1_x': ('alias', 'l_0_x'), 'l_1_item': ('param', None), 'l_1_expression': ('resolve', 'expression'), }
def parse(self, parser): lineno = next(parser.stream).lineno # Get the block selection from the tag argument. block_selection = parser.parse_expression() # Make "Name" node for "For" node target. block_name = nodes.Name('_ext_ob_blknm', 'store') # For each block, add an "If" node checking if it matches the target. # Also record the original "default" ordering of the blocks. blocks = [] block_names = [] for node in parser.parse_statements(['name:endorderblocks'], drop_needle=True): if isinstance(node, nodes.Block): blocks.append(nodes.If( nodes.Compare( block_name, [nodes.Operand('eq', nodes.Const(node.name))]), [node], [])) block_names.append(node.name) # Make a "For" node iterating over the given block selection. If the # block selection is undefined or None then use the original ordering. return nodes.For( block_name, nodes.CondExpr( nodes.And( nodes.Test(block_selection, 'defined', [], [], None, None), nodes.Not( nodes.Test(block_selection, 'none', [], [], None, None)), ), block_selection, nodes.Tuple([nodes.Const(x) for x in block_names], 'store')), blocks, [], None, False)
def test_complex(): title_block = nodes.Block( "title", [nodes.Output([nodes.TemplateData(u"Page Title")])], False) render_title_macro = nodes.Macro( "render_title", [nodes.Name("title", "param")], [], [ nodes.Output([ nodes.TemplateData(u'\n <div class="title">\n <h1>'), nodes.Name("title", "load"), nodes.TemplateData(u"</h1>\n <p>"), nodes.Name("subtitle", "load"), nodes.TemplateData(u"</p>\n "), ]), nodes.Assign(nodes.Name("subtitle", "store"), nodes.Const("something else")), nodes.Output([ nodes.TemplateData(u"\n <p>"), nodes.Name("subtitle", "load"), nodes.TemplateData(u"</p>\n </div>\n"), nodes.If( nodes.Name("something", "load"), [ nodes.Assign( nodes.Name("title_upper", "store"), nodes.Filter( nodes.Name("title", "load"), "upper", [], [], None, None, ), ), nodes.Output([ nodes.Name("title_upper", "load"), nodes.Call( nodes.Name("render_title", "load"), [nodes.Const("Aha")], [], None, None, ), ]), ], [], [], ), ]), ], ) for_loop = nodes.For( nodes.Name("item", "store"), nodes.Name("seq", "load"), [ nodes.Output([ nodes.TemplateData(u"\n <li>"), nodes.Name("item", "load"), nodes.TemplateData(u"</li>\n <span>"), ]), nodes.Include(nodes.Const("helper.html"), True, False), nodes.Output([nodes.TemplateData(u"</span>\n ")]), ], [], None, False, ) body_block = nodes.Block( "body", [ nodes.Output([ nodes.TemplateData(u"\n "), nodes.Call( nodes.Name("render_title", "load"), [nodes.Name("item", "load")], [], None, None, ), nodes.TemplateData(u"\n <ul>\n "), ]), for_loop, nodes.Output([nodes.TemplateData(u"\n </ul>\n")]), ], False, ) tmpl = nodes.Template([ nodes.Extends(nodes.Const("layout.html")), title_block, render_title_macro, body_block, ]) tmpl_sym = symbols_for_node(tmpl) assert tmpl_sym.refs == { "render_title": "l_0_render_title", } assert tmpl_sym.loads == { "l_0_render_title": ("undefined", None), } assert tmpl_sym.stores == set(["render_title"]) assert tmpl_sym.dump_stores() == { "render_title": "l_0_render_title", } macro_sym = symbols_for_node(render_title_macro, tmpl_sym) assert macro_sym.refs == { "subtitle": "l_1_subtitle", "something": "l_1_something", "title": "l_1_title", "title_upper": "l_1_title_upper", } assert macro_sym.loads == { "l_1_subtitle": ("resolve", "subtitle"), "l_1_something": ("resolve", "something"), "l_1_title": ("param", None), "l_1_title_upper": ("resolve", "title_upper"), } assert macro_sym.stores == set(["title", "title_upper", "subtitle"]) assert macro_sym.find_ref("render_title") == "l_0_render_title" assert macro_sym.dump_stores() == { "title": "l_1_title", "title_upper": "l_1_title_upper", "subtitle": "l_1_subtitle", "render_title": "l_0_render_title", } body_sym = symbols_for_node(body_block) assert body_sym.refs == { "item": "l_0_item", "seq": "l_0_seq", "render_title": "l_0_render_title", } assert body_sym.loads == { "l_0_item": ("resolve", "item"), "l_0_seq": ("resolve", "seq"), "l_0_render_title": ("resolve", "render_title"), } assert body_sym.stores == set([]) for_sym = symbols_for_node(for_loop, body_sym) assert for_sym.refs == { "item": "l_1_item", } assert for_sym.loads == { "l_1_item": ("param", None), } assert for_sym.stores == set(["item"]) assert for_sym.dump_stores() == { "item": "l_1_item", }
def test_complex(): title_block = nodes.Block('title', [ nodes.Output([nodes.TemplateData(u'Page Title')]) ], False) render_title_macro = nodes.Macro('render_title', [nodes.Name('title', 'param')], [], [ nodes.Output([ nodes.TemplateData(u'\n <div class="title">\n <h1>'), nodes.Name('title', 'load'), nodes.TemplateData(u'</h1>\n <p>'), nodes.Name('subtitle', 'load'), nodes.TemplateData(u'</p>\n ')]), nodes.Assign( nodes.Name('subtitle', 'store'), nodes.Const('something else')), nodes.Output([ nodes.TemplateData(u'\n <p>'), nodes.Name('subtitle', 'load'), nodes.TemplateData(u'</p>\n </div>\n'), nodes.If( nodes.Name('something', 'load'), [ nodes.Assign(nodes.Name('title_upper', 'store'), nodes.Filter(nodes.Name('title', 'load'), 'upper', [], [], None, None)), nodes.Output([ nodes.Name('title_upper', 'load'), nodes.Call(nodes.Name('render_title', 'load'), [ nodes.Const('Aha')], [], None, None)])], [])])]) for_loop = nodes.For( nodes.Name('item', 'store'), nodes.Name('seq', 'load'), [ nodes.Output([ nodes.TemplateData(u'\n <li>'), nodes.Name('item', 'load'), nodes.TemplateData(u'</li>\n <span>')]), nodes.Include(nodes.Const('helper.html'), True, False), nodes.Output([ nodes.TemplateData(u'</span>\n ')])], [], None, False) body_block = nodes.Block('body', [ nodes.Output([ nodes.TemplateData(u'\n '), nodes.Call(nodes.Name('render_title', 'load'), [ nodes.Name('item', 'load')], [], None, None), nodes.TemplateData(u'\n <ul>\n ')]), for_loop, nodes.Output([nodes.TemplateData(u'\n </ul>\n')])], False) tmpl = nodes.Template([ nodes.Extends(nodes.Const('layout.html')), title_block, render_title_macro, body_block, ]) tmpl_sym = symbols_for_node(tmpl) assert tmpl_sym.refs == { 'render_title': 'l_0_render_title', } assert tmpl_sym.loads == { 'l_0_render_title': ('undefined', None), } assert tmpl_sym.stores == set(['render_title']) assert tmpl_sym.dump_stores() == { 'render_title': 'l_0_render_title', } macro_sym = symbols_for_node(render_title_macro, tmpl_sym) assert macro_sym.refs == { 'subtitle': 'l_1_subtitle', 'something': 'l_1_something', 'title': 'l_1_title', 'title_upper': 'l_1_title_upper', } assert macro_sym.loads == { 'l_1_subtitle': ('resolve', 'subtitle'), 'l_1_something': ('resolve','something'), 'l_1_title': ('param', None), 'l_1_title_upper': ('resolve', 'title_upper'), } assert macro_sym.stores == set(['title', 'title_upper', 'subtitle']) assert macro_sym.find_ref('render_title') == 'l_0_render_title' assert macro_sym.dump_stores() == { 'title': 'l_1_title', 'title_upper': 'l_1_title_upper', 'subtitle': 'l_1_subtitle', 'render_title': 'l_0_render_title', } body_sym = symbols_for_node(body_block) assert body_sym.refs == { 'item': 'l_0_item', 'seq': 'l_0_seq', 'render_title': 'l_0_render_title', } assert body_sym.loads == { 'l_0_item': ('resolve', 'item'), 'l_0_seq': ('resolve', 'seq'), 'l_0_render_title': ('resolve', 'render_title'), } assert body_sym.stores == set([]) for_sym = symbols_for_node(for_loop, body_sym) assert for_sym.refs == { 'item': 'l_1_item', } assert for_sym.loads == { 'l_1_item': ('param', None), } assert for_sym.stores == set(['item']) assert for_sym.dump_stores() == { 'item': 'l_1_item', }
def tablerow( token: "Token", parser: "Parser" ) -> Union[nodes.Node, List[nodes.Node]]: """The tablerow tag {% tablerow ... %} ... {% endtablerow %} Args: token: The token matches tag name parser: The parser Returns: The parsed node """ target = parser.parse_assign_target(extra_end_rules=("name:in", )) parser.stream.expect("name:in") iter_ = parser.parse_tuple( with_condexpr=False, extra_end_rules=("name:cols", "name:limit", "name:offset"), ) cols = parse_tag_args(parser.stream, "cols", token.lineno) limit = parse_tag_args(parser.stream, "limit", token.lineno) offset = parse_tag_args(parser.stream, "offset", token.lineno) if limit and offset: limit = nodes.Add(offset, limit) if limit or offset: iter_ = nodes.Getitem(iter_, nodes.Slice(offset, limit, None), "load") if cols: slice_start = nodes.Mul(nodes.Name("_tablerow_i", "load"), cols) inner_iter = nodes.Getitem( iter_, nodes.Slice( slice_start, nodes.Add(slice_start, cols), None, ), "load", ) else: inner_iter: nodes.Getitem = iter_ inner_body = [ nodes.Output( [ nodes.Const('<td class="col'), nodes.Getattr(nodes.Name("loop", "load"), "index", "load"), nodes.Const('">'), ] ), *parser.parse_statements(("name:endtablerow",), drop_needle=True), nodes.Output([nodes.Const("</td>")]), ] tr_begin = nodes.Output( [ nodes.Const('<tr class="row'), nodes.CondExpr( nodes.Name("loop", "load"), nodes.Getattr(nodes.Name("loop", "load"), "index", "load"), nodes.Const(1), ), nodes.Const('">'), ] ) tr_end = nodes.Output([nodes.Const("</tr>")]) inner_loop = nodes.For( target, inner_iter, inner_body, [], None, False, lineno=token.lineno ) if not cols: return [tr_begin, inner_loop, tr_end] # (iter_ | length) / cols iter_length = nodes.Div( nodes.Filter(iter_, "length", [], [], None, None), cols, ) # float # int(iter_length) iter_length_int = nodes.Filter(iter_length, "int", [], [], None, None) # implement ceil, as jinja's ceil is implemented as round(..., "ceil") # while liquid has a ceil filter # iter_length_int if iter_length == iter_length_int # else iter_length_int + 1 iter_length = nodes.CondExpr( nodes.Compare(iter_length, [nodes.Operand("eq", iter_length_int)]), iter_length_int, nodes.Add(iter_length_int, nodes.Const(1)), ) return nodes.For( nodes.Name("_tablerow_i", "store"), nodes.Call(nodes.Name("range", "load"), [iter_length], [], None, None), [tr_begin, inner_loop, tr_end], [], None, False, lineno=token.lineno, )