def parse(self, parser): lineno = parser.stream.__next__().lineno value = parser.parse_expression() items_per_page_obj = parser.stream.next_if('integer') items_per_page = items_per_page_obj.value if items_per_page_obj else DEFAULT_PAGINATION if parser.stream.skip_if('name:as'): name = parser.stream.expect('name').value elif hasattr(value, 'name'): name = value.name else: raise TemplateSyntaxError("Cannot determine the name of objects you want to paginate, use 'as foobar' syntax", lineno) while not parser.stream.current.type == 'block_end': parser.stream.skip() return [ nodes.Assign(nodes.Name(name + '_pages', 'store'), self.call_method('_render_pages', [value, nodes.Name('request', 'load'), nodes.Const(items_per_page)]) ).set_lineno(lineno), nodes.Assign(nodes.Name(name, 'store'), nodes.Getattr(nodes.Name(name + '_pages', 'load'), 'object_list', nodes.Impossible()) ).set_lineno(lineno), ]
def parse_subscript(self, node): token = next(self.stream) if token.type == 'dot': attr_token = self.stream.current next(self.stream) if attr_token.type == 'name': return nodes.Getattr(node, attr_token.value, 'load', lineno=token.lineno) elif attr_token.type != 'integer': self.fail('expected name or number', attr_token.lineno) arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) return nodes.Getitem(node, arg, 'load', lineno=token.lineno) if token.type == 'lbracket': args = [] while self.stream.current.type != 'rbracket': if args: self.stream.expect('comma') args.append(self.parse_subscribed()) self.stream.expect('rbracket') if len(args) == 1: arg = args[0] else: arg = nodes.Tuple(args, 'load', lineno=token.lineno) return nodes.Getitem(node, arg, 'load', lineno=token.lineno) self.fail('expected subscript expression', self.lineno)
def parse_part(self, parser, token): node = nodes.Macro(lineno=token.lineno) part_name = parser.stream.expect('name').value node.name = "compopart_" + part_name parser.parse_signature(node) node.args = [ nodes.Name("self", "param"), nodes.Name("has_caller", "param") ] + node.args # + [nodes.Name("caller", "param")] assign_node = nodes.Assign() assign_node.target = nodes.Name("dummy", "store") call_node = nodes.Call() call_node.node = nodes.Getattr() call_node.node.node = nodes.Name("self", "load") call_node.node.attr = "overwrite_compopart" # calls the method "self.overwrite_compopart()" from the components call_node.node.ctx = "load" call_node.args = [ nodes.Const(part_name), nodes.Name('compopart_' + part_name, 'load') ] call_node.kwargs = [] call_node.dyn_args = None call_node.dyn_kwargs = None assign_node.node = call_node node.body = parser.parse_statements(('name:endcompopart', ), drop_needle=True) return [node, assign_node]
def parse_subscript(self, node): token = next(self.stream) if token.type == "dot": attr_token = self.stream.current next(self.stream) if attr_token.type == "name": return nodes.Getattr(node, attr_token.value, "load", lineno=token.lineno) elif attr_token.type != "integer": self.fail("expected name or number", attr_token.lineno) arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) return nodes.Getitem(node, arg, "load", lineno=token.lineno) if token.type == "lbracket": args = [] while self.stream.current.type != "rbracket": if args: self.stream.expect("comma") args.append(self.parse_subscribed()) self.stream.expect("rbracket") if len(args) == 1: arg = args[0] else: arg = nodes.Tuple(args, "load", lineno=token.lineno) return nodes.Getitem(node, arg, "load", lineno=token.lineno) self.fail("expected subscript expression", self.lineno)
def parse(self, parser): node = nodes.ExprStmt(lineno=next(parser.stream).lineno) modules = [] while parser.stream.current.type != 'block_end': lineno = parser.stream.current.lineno if modules: parser.stream.expect('comma') expr = parser.parse_expression() module = expr.as_const() modules.append(module) assignments = [] from djinja.template.defaultfunctions import Load for m in modules: target = nodes.Name(m, 'store') func = nodes.Call(nodes.Name('load', 'load'), [nodes.Const(m)], [], None, None) assignments.append(nodes.Assign(target, func, lineno=lineno)) for i in Load(m).globals.keys(): target = nodes.Name(i, 'store') f = nodes.Getattr(nodes.Name(m, 'load'), i, 'load') assignments.append(nodes.Assign(target, f, lineno=lineno)) return assignments
def parse(self, parser): self.parser = parser lineno = parser.stream.expect('name:csrf_token_raw').lineno call = self.call_method('_csrf_token', [ nodes.Getattr(nodes.Name('request', 'load'), 'csrf_token', 'load') ], lineno=lineno) return nodes.Output([nodes.MarkSafe(call)])
def parse(self, parser): lineno = parser.stream.next().lineno object_list = parser.parse_expression() if parser.stream.skip_if('name:as'): name = parser.stream.expect('name').value elif hasattr(object_list, 'name'): name = object_list.name else: raise TemplateSyntaxError( "Cannot determine the name of objects " \ "you want to paginate, use 'as foobar' syntax", lineno) kwargs = [] # wait... what? loops = 0 while parser.stream.current.type != 'block_end': lineno = parser.stream.current.lineno if loops: parser.stream.expect('comma') key = parser.parse_assign_target().name if key not in self.default_kwargs.keys(): raise TemplateSyntaxError( "Unknown keyword argument for autopaginate. "\ "Your options are: %s" % ( ", ".join(self.default_kwargs.keys()) )) parser.stream.expect('assign') value = parser.parse_expression() kwargs.append(nodes.Keyword(key, value)) loops += 1 return [ nodes.Assign(nodes.Name(name + '_pages', 'store'), self.call_method('_render_pages', [object_list, nodes.Name('request', 'load')], kwargs) ).set_lineno(lineno), nodes.Assign(nodes.Name(name, 'store'), nodes.Getattr(nodes.Name(name + '_pages', 'load'), 'object_list', nodes.Impossible()) ).set_lineno(lineno), ]
def cycle(token: "Token", parser: "Parser") -> nodes.Node: """The cycle tag {% cycle ... %} With name: {% cycle "name": "one", "two", "three" %} Without: {% cycle "one", "two", "three" %} Turn these to {{ loop.liquid_cycle("one", "two", "three", name=...) }} Args: token: The token matches tag name parser: The parser Returns: The parsed node """ tokens_ahead = peek_tokens(parser.stream, 2) if ( len(tokens_ahead) == 2 and tokens_ahead[0].type is TOKEN_STRING and tokens_ahead[1].type is TOKEN_COLON ): parser.stream.skip(2) cycler_name = tokens_ahead[0].value else: cycler_name = "" args = parser.parse_tuple(with_condexpr=False, simplified=True) return nodes.Output( [ nodes.Call( nodes.Getattr( nodes.Name("loop", "load"), "liquid_cycle", "load" ), args.items if isinstance(args, nodes.Tuple) else [args], [nodes.Keyword("name", nodes.Const(cycler_name))], None, None, lineno=token.lineno, ) ] )
def parse(self, parser): # Get the component for the tag name that we matched on tag_name = parser.stream.current[2] component_class = self.environment.components[tag_name] field_names = [f.name for f in dataclasses.fields(component_class)] has_children = CHILDREN_FIELD_NAME in field_names lineno = next(parser.stream).lineno node = nodes.Scope(lineno=lineno) # list of `Pair` nodes for tag properties to update "component" dictionary component_dict_update_items = [] while parser.stream.current.type != 'block_end': lineno = parser.stream.current.lineno if component_dict_update_items: parser.stream.expect('comma') name = parser.stream.expect('name') parser.stream.expect('assign') value = parser.parse_expression() component_dict_update_items.append( nodes.Pair(nodes.Const(name.value), value)) # dictionary initialization in the "component" name prepare_component_dict = [ self._initialize_component_dict(component_class, lineno) ] if component_dict_update_items: component_dict_delta = nodes.Dict(component_dict_update_items) # `Getattr` for "update" function of the dictionary "component" update_component_dict_fun = nodes.Getattr( nodes.Name(TMP_COMPONENT_DICT_NAME, 'load'), 'update', 'load') # `Call` for `component.update(<prop name>, <prop value>)` call_component_dict_update = nodes.Call(update_component_dict_fun, [component_dict_delta], [], None, None) prepare_component_dict.append( nodes.ExprStmt(call_component_dict_update)) # assign `component = __component` and `__component = None` prepare_component_dict.extend([ nodes.Assign(nodes.Name(COMPONENT_DICT_NAME, 'store', lineno=lineno), nodes.Name(TMP_COMPONENT_DICT_NAME, 'load', lineno=lineno), lineno=lineno), nodes.Assign(nodes.Name(TMP_COMPONENT_DICT_NAME, 'store', lineno=lineno), nodes.Const(None, lineno=lineno), lineno=lineno) ]) if has_children: inner_block = list( parser.parse_statements(('name:end' + tag_name, ), drop_needle=True)) # create children() macro children_macro = nodes.Macro() children_macro.name = CHILDREN_MACRO_NAME children_macro.args = [] children_macro.defaults = [] children_macro.body = inner_block children_macro_nodes = [children_macro] else: children_macro_nodes = [] # include tag template include_tag = nodes.Include() # use `template` item of the "component" dictionary for template path include_tag.template = nodes.Getitem(nodes.Name(COMPONENT_DICT_NAME, 'load', lineno=lineno), nodes.Const(TEMPLATE_FIELD_NAME, lineno=lineno), 'load', lineno=lineno) include_tag.ignore_missing = False include_tag.with_context = True node.body = prepare_component_dict + children_macro_nodes + [ include_tag, ] return node
def process_cache_arguments(self, args): args.append(nodes.Getattr(nodes.ContextReference(), 'request', 'load'))
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, )