Example #1
0
    def _make_node(self, singular, plural, variables, plural_expr,
                   vars_referenced, num_called_num):
        """Generates a useful node from the data provided."""
        if not vars_referenced and not self.environment.newstyle_gettext:
            singular = singular.replace('%%', '%')
            if plural:
                plural = plural.replace('%%', '%')
        if plural_expr is None:
            gettext = nodes.Name('gettext', 'load')
            node = nodes.Call(gettext, [nodes.Const(singular)], [], None, None)
        else:
            ngettext = nodes.Name('ngettext', 'load')
            node = nodes.Call(
                ngettext,
                [nodes.Const(singular),
                 nodes.Const(plural), plural_expr], [], None, None)
        if self.environment.newstyle_gettext:
            for key, value in variables.iteritems():
                if num_called_num and key == 'num':
                    continue
                node.kwargs.append(nodes.Keyword(key, value))

        else:
            node = nodes.MarkSafeIfAutoescape(node)
            if variables:
                node = nodes.Mod(
                    node,
                    nodes.Dict([
                        nodes.Pair(nodes.Const(key), value)
                        for key, value in variables.items()
                    ]))
        return nodes.Output([node])
Example #2
0
    def _make_node(self, singular, plural, variables, plural_expr):
        """Generates a useful node from the data provided."""
        # singular only:
        if plural_expr is None:
            gettext = nodes.Name('gettext', 'load')
            node = nodes.Call(gettext, [nodes.Const(singular)],
                              [], None, None)

        # singular and plural
        else:
            ngettext = nodes.Name('ngettext', 'load')
            node = nodes.Call(ngettext, [
                nodes.Const(singular),
                nodes.Const(plural),
                plural_expr
            ], [], None, None)

        # mark the return value as safe if we are in an
        # environment with autoescaping turned on
        if self.environment.autoescape:
            node = nodes.MarkSafe(node)

        if variables:
            node = nodes.Mod(node, variables)
        return nodes.Output([node])
Example #3
0
    def _make_node(
        self, singular, plural, variables, plural_expr, vars_referenced, num_called_num
    ):
        """Generates a useful node from the data provided."""
        # no variables referenced?  no need to escape for old style
        # gettext invocations only if there are vars.
        if not vars_referenced and not self.environment.newstyle_gettext:
            singular = singular.replace("%%", "%")
            if plural:
                plural = plural.replace("%%", "%")

        # singular only:
        if plural_expr is None:
            gettext = nodes.Name("gettext", "load")
            node = nodes.Call(gettext, [nodes.Const(singular)], [], None, None)

        # singular and plural
        else:
            ngettext = nodes.Name("ngettext", "load")
            node = nodes.Call(
                ngettext,
                [nodes.Const(singular), nodes.Const(plural), plural_expr],
                [],
                None,
                None,
            )

        # in case newstyle gettext is used, the method is powerful
        # enough to handle the variable expansion and autoescape
        # handling itself
        if self.environment.newstyle_gettext:
            for key, value in iteritems(variables):
                # the function adds that later anyways in case num was
                # called num, so just skip it.
                if num_called_num and key == "num":
                    continue
                node.kwargs.append(nodes.Keyword(key, value))

        # otherwise do that here
        else:
            # mark the return value as safe if we are in an
            # environment with autoescaping turned on
            node = nodes.MarkSafeIfAutoescape(node)
            if variables:
                node = nodes.Mod(
                    node,
                    nodes.Dict(
                        [
                            nodes.Pair(nodes.Const(key), value)
                            for key, value in variables.items()
                        ]
                    ),
                )
        return nodes.Output([node])
Example #4
0
    def parse(self, parser):
        lineno = next(parser.stream).lineno
        expr = parser.parse_expression()
        args = [expr]
        kwargs = [nodes.Keyword('func', expr)]
        if parser.stream.skip_if('comma'):
            # Optional 'note' for function docstring
            if (parser.stream.current.type == 'name'
                    and parser.stream.current.value
                    in ('note', 'cond_for', 'depends_on')):
                stream_type = parser.stream.current.value
                next(parser.stream)
                parser.stream.expect('assign')
                # Depends meta is always a list
                if stream_type == 'depends_on':
                    c_expr = parser.parse_list()
                else:
                    c_expr = parser.parse_expression()
                args.append(c_expr)
                kwargs.append(nodes.Keyword(stream_type, c_expr))

        body = parser.parse_statements(['name:endsql', 'name:endquery'],
                                       drop_needle=True)
        raw_template = self.environment.sql_params['raws'][parser.name]

        # Lines range of original raw template
        raw_lines = slice(lineno, parser.stream.current.lineno - 1)
        self.environment.sql_params.setdefault('funcs', {}).update(
            {expr.value: {
                'raw_sql': '\n '.join(raw_template[raw_lines])
            }})
        call_node = nodes.Call(self.attr('_sql_process', lineno=lineno), args,
                               kwargs, None, None)
        return nodes.CallBlock(call_node, [], [], body)
Example #5
0
    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
Example #6
0
        def parse_formrow(self, parser, tag):
            lineno = tag.lineno
            field = parser.parse_expression()
            template_name = None
            if not parser.stream.current.test('block_end'):
                template_name = parser.parse_expression()
            else:
                template_name = nodes.Call(
                    nodes.Name('get_formrow_template', 'load'),
                    [],
                    [
                        nodes.Keyword('caller_template',
                                      nodes.Const(parser.name)),
                        nodes.Keyword('form',
                                      nodes.Name('form_utils_form', 'load'))
                    ],
                    None,
                    None,
                )
            if not parser.stream.current.test('block_end'):
                raise TemplateSyntaxError("Too many arguments", lineno)

            node = nodes.Scope(lineno=lineno)
            assignments = [nodes.Assign(nodes.Name('field', 'store'), field)]
            node.body = assignments + [
                nodes.Include(template_name, True, False)
            ]
            return node.set_lineno(lineno)
Example #7
0
    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]
Example #8
0
    def parse_trs(self, parser, lineno):
        lineno = lineno
        args = [parser.parse_expression()]
        variables = {}

        while parser.stream.current.type != 'block_end':
            parser.stream.expect('comma')
            name = parser.stream.expect('name')
            if name.value in variables:
                parser.fail('translatable variable %r defined twice.' %
                            name.value,
                            name.lineno,
                            exc=TemplateAssertionError)
            if parser.stream.current.type == 'assign':
                next(parser.stream)
                variables[name.value] = var = parser.parse_expression()
            else:
                variables[name.value] = var = nodes.Name(name.value, 'load')
        kwargs = []
        if 'description' in variables:
            kwargs = [
                nodes.Keyword('description', variables.get('description', ''))
            ]

        return nodes.Output([
            nodes.Call(nodes.Name('translate_trs', 'load'), args, kwargs, None,
                       None)
        ]).set_lineno(lineno)
Example #9
0
    def parse_load(self, parser):
        filter_name = parser.stream.current.value
        lineno = next(parser.stream).lineno
        if filter_name not in self.environment.filters:
            parser.fail("Unable to parse {0}".format(filter_name), lineno)

        parser.stream.expect("name:as")
        target = parser.parse_assign_target()
        macro_name = "_" + parser.free_identifier().name
        macro_body = parser.parse_statements(("name:endload", ),
                                             drop_needle=True)

        return [
            nodes.Macro(macro_name, [], [], macro_body).set_lineno(lineno),
            nodes.Assign(
                target,
                nodes.Filter(
                    nodes.Call(
                        nodes.Name(macro_name, "load").set_lineno(lineno),
                        [],
                        [],
                        None,
                        None,
                    ).set_lineno(lineno),
                    filter_name,
                    [],
                    [],
                    None,
                    None,
                ).set_lineno(lineno),
            ).set_lineno(lineno),
        ]
Example #10
0
 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)
Example #11
0
    def _parse_trans(self, parser, lineno):
        string = parser.stream.expect(lexer.TOKEN_STRING)
        string = nodes.Const(string.value, lineno=string.lineno)
        is_noop = False
        context = None
        as_var = None
        for token in iter(lambda: parser.stream.next_if(lexer.TOKEN_NAME),
                          None):
            if token.value == 'noop' and not is_noop:
                if context is not None:
                    parser.fail("noop translation can't have context",
                                lineno=token.lineno)
                is_noop = True
            elif token.value == 'context' and context is None:
                if is_noop:
                    parser.fail("noop translation can't have context",
                                lineno=token.lineno)
                context = parser.stream.expect(lexer.TOKEN_STRING)
                context = nodes.Const(context.value, lineno=context.lineno)
            elif token.value == 'as' and as_var is None:
                as_var = parser.stream.expect(lexer.TOKEN_NAME)
                as_var = nodes.Name(as_var.value,
                                    'store',
                                    lineno=as_var.lineno)
            else:
                parser.fail("expected 'noop', 'context' or 'as'",
                            lineno=token.lineno)
        if is_noop:
            output = string
        elif context is not None:
            func = nodes.Name('pgettext', 'load', lineno=lineno)
            output = nodes.Call(func, [context, string], [],
                                None,
                                None,
                                lineno=lineno)
        else:
            func = nodes.Name('gettext', 'load')
            output = nodes.Call(func, [string], [], None, None, lineno=lineno)

        if as_var is None:
            return nodes.Output([output], lineno=lineno)
        else:
            return nodes.Assign(as_var, output, lineno=lineno)
Example #12
0
 def call_method(self, name, args=None, kwargs=None, dyn_args=None,
                 dyn_kwargs=None, lineno=None):
     """Call a method of the extension.  This is a shortcut for
     :meth:`attr` + :class:`jinja2.nodes.Call`.
     """
     if args is None:
         args = []
     if kwargs is None:
         kwargs = []
     return nodes.Call(self.attr(name, lineno=lineno), args, kwargs,
                       dyn_args, dyn_kwargs, lineno=lineno)
Example #13
0
    def parse(self, parser):
        is_block = parser.stream.current.test("name:call_macro_tag")
        lineno = parser.stream.__next__().lineno
        macro_name = self.environment.macros.resolve_alias(parser.stream.current.value)
        parser.stream.__next__()
        args, kwargs = parse_macro_tag_signature(parser)

        call = nodes.Call(nodes.Name(macro_name, "load"), args, kwargs, None, None, lineno=lineno)
        if is_block:
            body = parser.parse_statements(['name:endmacrotag'], drop_needle=True)
            return nodes.CallBlock(call, [], {}, body, lineno=lineno)
        return nodes.Output([call])
Example #14
0
    def parse_call(self, node):
        token = self.stream.expect('lparen')
        args = []
        kwargs = []
        dyn_args = dyn_kwargs = None
        require_comma = False

        def ensure(expr):
            if not expr:
                self.fail('invalid syntax for function call expression',
                          token.lineno)

        while self.stream.current.type != 'rparen':
            if require_comma:
                self.stream.expect('comma')
                # support for trailing comma
                if self.stream.current.type == 'rparen':
                    break
            if self.stream.current.type == 'mul':
                ensure(dyn_args is None and dyn_kwargs is None)
                next(self.stream)
                dyn_args = self.parse_expression()
            elif self.stream.current.type == 'pow':
                ensure(dyn_kwargs is None)
                next(self.stream)
                dyn_kwargs = self.parse_expression()
            else:
                if self.stream.current.type == 'name' and \
                   self.stream.look().type == 'assign':
                    # Parsing a kwarg
                    ensure(dyn_kwargs is None)
                    key = self.stream.current.value
                    self.stream.skip(2)
                    value = self.parse_expression()
                    kwargs.append(
                        nodes.Keyword(key, value, lineno=value.lineno))
                else:
                    # Parsing an arg
                    ensure(dyn_args is None and dyn_kwargs is None
                           and not kwargs)
                    args.append(self.parse_expression())

            require_comma = True
        self.stream.expect('rparen')

        if node is None:
            return args, kwargs, dyn_args, dyn_kwargs
        return nodes.Call(node,
                          args,
                          kwargs,
                          dyn_args,
                          dyn_kwargs,
                          lineno=token.lineno)
Example #15
0
    def parse_call(self, node):
        token = self.stream.expect("lparen")
        args = []
        kwargs = []
        dyn_args = dyn_kwargs = None
        require_comma = False

        def ensure(expr):
            if not expr:
                self.fail("invalid syntax for function call expression",
                          token.lineno)

        while self.stream.current.type != "rparen":
            if require_comma:
                self.stream.expect("comma")
                # support for trailing comma
                if self.stream.current.type == "rparen":
                    break
            if self.stream.current.type == "mul":
                ensure(dyn_args is None and dyn_kwargs is None)
                next(self.stream)
                dyn_args = self.parse_expression()
            elif self.stream.current.type == "pow":
                ensure(dyn_kwargs is None)
                next(self.stream)
                dyn_kwargs = self.parse_expression()
            else:
                ensure(dyn_args is None and dyn_kwargs is None)
                if (self.stream.current.type == "name"
                        and self.stream.look().type == "assign"):
                    key = self.stream.current.value
                    self.stream.skip(2)
                    value = self.parse_expression()
                    kwargs.append(
                        nodes.Keyword(key, value, lineno=value.lineno))
                else:
                    ensure(not kwargs)
                    args.append(self.parse_expression())

            require_comma = True
        self.stream.expect("rparen")

        if node is None:
            return args, kwargs, dyn_args, dyn_kwargs
        return nodes.Call(node,
                          args,
                          kwargs,
                          dyn_args,
                          dyn_kwargs,
                          lineno=token.lineno)
Example #16
0
 def parse_tr(self, parser, lineno):
     node = nodes.Scope(lineno=lineno)
     assignments = []
     while parser.stream.current.type != 'block_end':
         lineno = parser.stream.current.lineno
         if assignments:
             parser.stream.expect('comma')
         target = parser.parse_assign_target(name_only=True)
         parser.stream.expect('assign')
         expr = parser.parse_expression()
         assignments.append(nodes.Keyword(target.name, expr, lineno=lineno))
     body = parser.parse_statements(('name:endtr', ), drop_needle=True)
     return nodes.CallBlock(
         nodes.Call(nodes.Name('translate_tr', 'load'), [], assignments,
                    None, None), [], [], body).set_lineno(lineno)
Example #17
0
 def call_method(self,
                 name,
                 args=None,
                 kwargs=None,
                 dyn_args=None,
                 dyn_kwargs=None,
                 lineno=None):
     if args is None:
         args = []
     if kwargs is None:
         kwargs = []
     return nodes.Call(self.attr(name, lineno=lineno),
                       args,
                       kwargs,
                       dyn_args,
                       dyn_kwargs,
                       lineno=lineno)
Example #18
0
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,
            )
        ]
    )
Example #19
0
    def test_is_method_call(self):
        node = self.env.parse('{{ foo() }}').find(nodes.Call)
        assert is_method_call(node, 'foo') is True
        assert is_method_call(node, 'bar') is False

        node = self.env.parse('{{ foo }}').find(nodes.Name)
        assert is_method_call(node, 'foo') is False

        node = nodes.Call()
        node.node = None
        assert is_method_call(node, 'foo') is False

        node = self.env.parse('{{ foo.bar.baz() }}').find(nodes.Call)
        assert is_method_call(node, 'baz') is True
        assert is_method_call(node, 'bar') is False
        assert is_method_call(node, 'foo') is False
        assert is_method_call(node, ('foo', 'bar', 'baz')) is True

        node = self.env.parse('{{ foo["bar"]() }}').find(nodes.Call)
        assert is_method_call(node, 'bar') is True
Example #20
0
        def parse_form(self, parser, tag):
            lineno = tag.lineno
            form_instance = parser.parse_expression()
            template_name = nodes.Call(
                nodes.Name('get_formlayout_template', 'load'),
                [],
                [
                    nodes.Keyword('caller_template', nodes.Const(parser.name)),
                    nodes.Keyword('form', form_instance),
                ],
                None,
                None,
            )
            has_body = False
            if not parser.stream.current.test('block_end'):
                parser.stream.expect('name:using')
                if parser.stream.current.test('block_end'):
                    has_body = True
            if not parser.stream.current.test('block_end'):
                template_name = parser.parse_expression()
            if not parser.stream.current.test('block_end'):
                raise TemplateSyntaxError("Too many arguments", lineno)

            body = None
            if has_body:
                body = parser.parse_statements(['name:endform'],
                                               drop_needle=True)
            else:
                body = nodes.Include(template_name, True, False)
                body = [body]

            node = nodes.Scope(lineno=lineno)
            assignments = [
                nodes.Assign(nodes.Name('form_utils_form', 'store'),
                             form_instance)
            ]
            node.body = assignments + body
            return node.set_lineno(lineno)
Example #21
0
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,
    )
Example #22
0
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',
    }
Example #23
0

class Builtin(object):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return self.name


# Fields used by nodes.If().
IF_NODE_FIELDS = {
    'test':
    nodes.Not(
        nodes.Call(nodes.Const(Builtin('isinstance')), [
            nodes.Name(DJEDI_NODE_STORAGE, 'load'),
            nodes.Const(Builtin('dict')),
        ], [], None, None)),
    'body': [
        nodes.Assign(nodes.Name(DJEDI_NODE_STORAGE, 'store'), nodes.Dict([])),
    ],
}

# Construct the Jinja2 AST equivalent of:
#
#   if not isinstance(DJEDI_NODE_STORAGE, dict):
#       DJEDI_NODE_STORAGE = {}
#
if nodes.If.fields == ('test', 'body', 'elif_', 'else_'):
    # Jinja 2.10 added the "elif" field to If()
    DJEDI_NODE_STORAGE_NODE = (
        nodes.If(
Example #24
0
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",
    }
Example #25
0
    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