def parse_usemacro(parser, token): try: args = token.split_contents() tag_name, macro_name, values = args[0], args[1], args[2:] except IndexError: m = ("'%s' tag requires at least one argument (macro name)" % token.contents.split()[0]) raise template.TemplateSyntaxError, m try: macro = parser._macros[macro_name] except (AttributeError, KeyError): m = "Macro '%s' is not defined" % macro_name raise template.TemplateSyntaxError, m fe_kwargs = {} fe_args = [] for val in values: if "=" in val: # kwarg name, value = val.split("=") fe_kwargs[name] = FilterExpression(value, parser) else: # arg # no validation, go for it ... fe_args.append(FilterExpression(val, parser)) macro.name = macro_name macro.parser = parser return macro, fe_args, fe_kwargs
def getMacro(context): try: args = token.split_contents() tag_name, macro_name, values = args[0], args[1], args[2:] except IndexError: raise template.TemplateSyntaxError, "'%s' tag requires at least one argument (macro name)" % token.contents.split( )[0] resolved = FilterExpression(macro_name, parser).resolve(context) if resolved: macro_name = resolved try: macro = parser._macros[macro_name] except (AttributeError, KeyError): raise template.TemplateSyntaxError, "Macro '%s' is not defined" % macro_name if (len(values) != len(macro.args)): raise template.TemplateSyntaxError, "Macro '%s' was declared with %d parameters and used with %d parameter" % ( macro_name, len(macro.args), len(values)) filter_expressions = [] for val in values: if (val[0] == "'" or val[0] == '"') and (val[0] != val[-1]): raise template.TemplateSyntaxError, "Non-terminated string argument: %s" % val[ 1:] filter_expressions.append(FilterExpression(val, parser)) return macro, filter_expressions
def do_get_latest_objects_by_category(parser, token): """ Get the latest objects by category {% get_latest_objects_by_category category app_name model_name set_name [date_field] [number] as [var_name] %} """ proper_form = "{% get_latest_objects_by_category category app_name model_name set_name [date_field] [number] as [var_name] %}" bits = token.split_contents() if bits[-2] != 'as': raise TemplateSyntaxError("%s tag shoud be in the form: %s" % (bits[0], proper_form)) if len(bits) < 7: raise TemplateSyntaxError("%s tag shoud be in the form: %s" % (bits[0], proper_form)) if len(bits) > 9: raise TemplateSyntaxError("%s tag shoud be in the form: %s" % (bits[0], proper_form)) category = FilterExpression(bits[1], parser) app_label = FilterExpression(bits[2], parser) model_name = FilterExpression(bits[3], parser) set_name = FilterExpression(bits[4], parser) var_name = bits[-1] if bits[5] != 'as': date_field = FilterExpression(bits[5], parser) else: date_field = FilterExpression(None, parser) if bits[6] != 'as': num = FilterExpression(bits[6], parser) else: num = FilterExpression(None, parser) return LatestObjectsNode(var_name, category, app_label, model_name, set_name, date_field, num)
def do_usemacro(parser, token): try: args = token.split_contents() tag_name, macro_name, values = args[0], args[1], args[2:] except IndexError: raise template.TemplateSyntaxError('{0} tag requires at least ' 'one argument (macro name)'.format(token.contents.split()[0])) try: macro = parser._macros[macro_name] except (AttributeError, KeyError): raise template.TemplateSyntaxError('Macro "{0}" is not defined'.format( macro_name)) if (len(values) != len(macro.args)): raise template.TemplateSyntaxError( 'Macro {0} was declared with {1} parameters ' 'and used with {2} parameter'.format( macro_name, len(macro.args), len(values) ) ) filter_expressions = [] for val in values: if (val[0] == "'" or val[0] == '"') and (val[0] != val[-1]): raise template.TemplateSyntaxError( 'Non-terminated string argument: {0}'.format(val[1:])) filter_expressions.append(FilterExpression(val, parser)) return UseMacroNode(macro, filter_expressions)
def recursetree(parser, token): """ Iterates over the nodes in the tree, and renders the contained block for each node. This tag will recursively render children into the template variable {{ children }}. Only one database query is required (children are cached for the whole tree) Usage: <ul> {% recursetree nodes %} <li> {{ node.name }} {% if not node.is_leaf_node %} <ul> {{ children }} </ul> {% endif %} </li> {% endrecursetree %} </ul> """ bits = token.contents.split() if len(bits) != 2: raise template.TemplateSyntaxError('%s tag requires a queryset' % bits[0]) queryset_var = FilterExpression(bits[1], parser) template_nodes = parser.parse(('endrecursetree',)) parser.delete_first_token() return RecurseTreeNode(template_nodes, queryset_var)
def do_math(parser, token): """ Syntax: {% math <argument, ..> "expression" as var_name %} Evaluates a math expression in the current context and saves the value into a variable with the given name. "$<number>" is a placeholder in the math expression. It will be replaced by the value of the argument at index <number> - 1. Arguments are static values or variables immediately after 'math' tag and before the expression (the third last token). Example usage, {% math a b "min($1, $2)" as result %} {% math a|length b|length 3 "($1 + $2) % $3" as result %} """ tokens = token.split_contents() if len(tokens) < 5: raise TemplateSyntaxError("'math' tag requires at least 4 arguments") expr, as_, var_name = tokens[-3:] # strip quote if found if re.match(r'^(\'|")', expr): expr = expr.strip(expr[0]) args = [] for a in tokens[1:-3]: if a.find('|') != -1: args.append(FilterExpression(a, parser)) else: args.append(Variable(a)) return MathNode(var_name, expr, args)
def test_filter_args_count(self): p = Parser("") l = Library() @l.filter def no_arguments(value): pass @l.filter def one_argument(value, arg): pass @l.filter def one_opt_argument(value, arg=False): pass @l.filter def two_arguments(value, arg, arg2): pass @l.filter def two_one_opt_arg(value, arg, arg2=False): pass p.add_library(l) for expr in ( '1|no_arguments:"1"', '1|two_arguments', '1|two_arguments:"1"', '1|two_one_opt_arg', ): with self.assertRaises(TemplateSyntaxError): FilterExpression(expr, p) for expr in ( # Correct number of arguments '1|no_arguments', '1|one_argument:"1"', # One optional '1|one_opt_argument', '1|one_opt_argument:"1"', # Not supplying all '1|two_one_opt_arg:"1"', ): FilterExpression(expr, p)
def __init__(self, nodelist, parent=None): # prepend {{ block.super }} to meta tag p = Parser('') t = 'block.super' fe = FilterExpression(t, p) vn = VariableNode(fe) # i don't even know vn.source = (StringOrigin(UNKNOWN_SOURCE), ('a', {})) nodelist.insert(0, vn) # build block tag with block name "meta" super(MetaNode, self).__init__("meta-cascade", nodelist, parent)
def render(self, context): for i, arg in enumerate(self.macro.args): try: fe = self.fe_args[i] context[arg] = fe.resolve(context) except IndexError: context[arg] = "" for name, default in self.macro.kwargs.iteritems(): if name in self.fe_kwargs: context[name] = self.fe_kwargs[name].resolve(context) else: context[name] = FilterExpression(default, self.macro.parser).resolve(context) return self.macro.nodelist.render(context)
def get_category_drilldown(parser, token): """ Retrieves the specified category, its ancestors and its immediate children as an iterable. Syntax:: {% get_category_drilldown "category name" [using "app.Model"] as varname %} Example:: {% get_category_drilldown "/Grandparent/Parent" [using "app.Model"] as family %} or :: {% get_category_drilldown category_obj as family %} Sets family to:: Grandparent, Parent, Child 1, Child 2, Child n """ bits = token.split_contents() error_str = '%(tagname)s tag should be in the format {%% %(tagname)s ' \ '"category name" [using "app.Model"] as varname %%} or ' \ '{%% %(tagname)s category_obj as varname %%}.' if len(bits) == 4: if bits[2] != 'as': raise template.TemplateSyntaxError(error_str % {'tagname': bits[0]}) if bits[2] == 'as': varname = bits[3].strip("'\"") model = "categories.category" if len(bits) == 6: if bits[2] not in ('using', 'as') or bits[4] not in ('using', 'as'): raise template.TemplateSyntaxError(error_str % {'tagname': bits[0]}) if bits[2] == 'as': varname = bits[3].strip("'\"") model = bits[5].strip("'\"") if bits[2] == 'using': varname = bits[5].strip("'\"") model = bits[3].strip("'\"") category = FilterExpression(bits[1], parser) return CategoryDrillDownNode(category, varname, model)
def test_filter_parsing(self): c = {"article": {"section": "News"}} p = Parser("") def fe_test(s, val): self.assertEqual(FilterExpression(s, p).resolve(c), val) fe_test("article.section", "News") fe_test("article.section|upper", "NEWS") fe_test('"News"', "News") fe_test("'News'", "News") fe_test(r'"Some \"Good\" News"', 'Some "Good" News') fe_test(r'"Some \"Good\" News"', 'Some "Good" News') fe_test(r"'Some \'Bad\' News'", "Some 'Bad' News") fe = FilterExpression(r'"Some \"Good\" News"', p) self.assertEqual(fe.filters, []) self.assertEqual(fe.var, 'Some "Good" News') # Filtered variables should reject access of attributes beginning with # underscores. self.assertRaises(TemplateSyntaxError, FilterExpression, "article._hidden|upper", p)
def create_view_name(view_name): if django_version < (1, 5, 0): return view_name else: return FilterExpression('"%s"' % view_name, Parser([]))
def fe_test(s, val): self.assertEqual(FilterExpression(s, p).resolve(c), val)