Exemplo n.º 1
0
    def parse_text(self, parser):
        import_node = parser.parse_import()
        target = import_node.target
        lineno = import_node.lineno

        return [
            import_node,
            nodes.Assign(
                nodes.Name(target, 'store').set_lineno(lineno),
                nodes.Filter(
                    nodes.Name(target, 'load').set_lineno(lineno),
                    'load_text',
                    [],
                    [],
                    None,
                    None
                )
                .set_lineno(lineno)
            ).set_lineno(lineno)
        ]
Exemplo n.º 2
0
def test_if_branching_stores():
    tmpl = nodes.Template([
        nodes.If(
            nodes.Name('expression', 'load'),
            [nodes.Assign(nodes.Name('variable', 'store'), nodes.Const(42))],
            [], [])
    ])

    sym = symbols_for_node(tmpl)
    assert sym.refs == {
        'variable': 'l_0_variable',
        'expression': 'l_0_expression'
    }
    assert sym.stores == set(['variable'])
    assert sym.loads == {
        'l_0_variable': ('resolve', 'variable'),
        'l_0_expression': ('resolve', 'expression')
    }
    assert sym.dump_stores() == {
        'variable': 'l_0_variable',
    }
Exemplo n.º 3
0
    def parse(self, parser):
        stream = parser.stream

        tag = stream.next()

        # get view name
        if stream.current.test('string'):
            bundle_name = parser.parse_primary()
        else:
            bundle_name = parser.parse_expression()

        # get arguments
        args = []
        kwargs = []
        while not stream.current.test_any('block_end', 'name:as'):
            if args or kwargs:
                stream.expect('comma')
            if stream.current.test('name') and stream.look().test('assign'):
                key = nodes.Const(stream.next().value)
                stream.skip()
                value = parser.parse_expression()
                kwargs.append(nodes.Pair(key, value, lineno=key.lineno))
            else:
                args.append(parser.parse_expression())

        make_call_node = lambda *kw: \
            self.call_method('_build_tag',
                             args=[bundle_name,
                             nodes.List(args), nodes.Dict(kwargs)],
                             kwargs=kw)

        # if an as-clause is specified, write the result to context...
        if stream.next_if('name:as'):
            var = nodes.Name(stream.expect('name').value, 'store')
            call_node = make_call_node(
                nodes.Keyword('fail', nodes.Const(False)))
            return nodes.Assign(var, call_node)
        # ...otherwise print it out.
        else:
            return nodes.Output([make_call_node()]).set_lineno(tag.lineno)
Exemplo n.º 4
0
    def compile_expression(self, source, undefined_to_none=True):
        """A handy helper method that returns a callable that accepts keyword
        arguments that appear as variables in the expression.  If called it
        returns the result of the expression.

        This is useful if applications want to use the same rules as Jinja
        in template "configuration files" or similar situations.

        Example usage:

        >>> env = Environment()
        >>> expr = env.compile_expression('foo == 42')
        >>> expr(foo=23)
        False
        >>> expr(foo=42)
        True

        Per default the return value is converted to `None` if the
        expression returns an undefined value.  This can be changed
        by setting `undefined_to_none` to `False`.

        >>> env.compile_expression('var')() is None
        True
        >>> env.compile_expression('var', undefined_to_none=False)()
        Undefined

        **new in Jinja 2.1**
        """
        parser = Parser(self, source, state='variable')
        try:
            expr = parser.parse_expression()
            if not parser.stream.eos:
                raise TemplateSyntaxError('chunk after expression',
                                          parser.stream.current.lineno, None,
                                          None)
        except TemplateSyntaxError:
            self.handle_exception(sys.exc_info(), source_hint=source)
        body = [nodes.Assign(nodes.Name('result', 'store'), expr, lineno=1)]
        template = self.from_string(nodes.Template(body, lineno=1))
        return TemplateExpression(template, undefined_to_none)
Exemplo n.º 5
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)
        ]
Exemplo n.º 6
0
    def parse_import(self, parser, converter):
        import_node = parser.parse_import()
        target = import_node.target
        lineno = import_node.lineno

        body = [
            import_node,
            nodes.Assign(
                nodes.Name(target, "store").set_lineno(lineno),
                nodes.Filter(
                    nodes.Name(target, "load").set_lineno(lineno),
                    "load_{}".format(converter),
                    [],
                    [],
                    None,
                    None,
                ).set_lineno(lineno),
            ).set_lineno(lineno),
        ]
        return self._parse_profile_block(parser, import_node.template,
                                         "import_{}".format(converter), body,
                                         lineno)
Exemplo n.º 7
0
    def parse_component(self, parser, token):

        # first: just make a call to the corresponding macro of the component.
        # now define a second - nearly identical macro - for redrawing
        # "node" is the node which will be returned in place
        node = nodes.CallBlock(lineno=token.lineno)

        node.call = parser.parse_expression()

        if not isinstance(node.call, nodes.Call):
            parser.fail(
                'the component call must be a "call": {% compo compo_name() %}',
                node.lineno)
        component_name = node.call.node.name

        if parser.stream.current.type == 'lparen':
            parser.parse_signature(node)
        else:
            node.args = []
            node.defaults = []

        original_body = parser.parse_statements(('name:endcompo', ),
                                                drop_needle=True)

        # inject a {% set self = COMPO_OBJ %}
        assign_node = nodes.Assign()
        assign_node.target = nodes.Name("self", "store")
        assign_node.node = nodes.Name(component_name, "load")

        node.body = [assign_node
                     ] + original_body  # node gets the additional "self"-hack

        ##        # overwrites the local-name of the compo {% set COMPO_OBJ = self %}
        ##        rev_assign_node = nodes.Assign()
        ##        rev_assign_node.target = nodes.Name(component_name, "store")
        ##        rev_assign_node.node = nodes.Name("self", "load")

        return node
Exemplo n.º 8
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)
Exemplo n.º 9
0
    def parse_experiment_enrolled_alternative(self, parser):
        """
        Parse {% experiment_enrolled_alternative <experiment_name> %} tags
        """

        lineno = parser.stream.current.lineno

        # list of nodes that will be used when calling the callback:
        args = []

        # get experiment name from token
        experiment_name = parser.stream.current
        args.append(self._name_or_const(experiment_name))
        next(parser.stream)

        # we will also need the context in the callback:
        args.append(nodes.ContextReference())

        # expecting `as` after the alternatives:
        if not self._token_as(parser):
            raise TemplateSyntaxError(
                'Syntax should be like: '
                '{% experiment_enrolled_alternative "experiment_name"'
                ' as some_variable %}',
                lineno,
            )
        next(parser.stream)

        # parse what comes after `as`:
        target = parser.parse_assign_target()

        # create a callback node that will be executed on render:
        call_node = self.call_method('render_experiment_enrolled_alternative',
                                     args,
                                     lineno=lineno)

        # return an assignment node that will trigger the callback:
        return nodes.Assign(target, call_node, lineno=lineno)
Exemplo n.º 10
0
def test_if_branching_stores():
    tmpl = nodes.Template([
        nodes.If(
            nodes.Name("expression", "load"),
            [nodes.Assign(nodes.Name("variable", "store"), nodes.Const(42))],
            [],
            [],
        )
    ])

    sym = symbols_for_node(tmpl)
    assert sym.refs == {
        "variable": "l_0_variable",
        "expression": "l_0_expression"
    }
    assert sym.stores == set(["variable"])
    assert sym.loads == {
        "l_0_variable": ("resolve", "variable"),
        "l_0_expression": ("resolve", "expression"),
    }
    assert sym.dump_stores() == {
        "variable": "l_0_variable",
    }
Exemplo n.º 11
0
    def _initialize_component_dict(component_class, lineno):
        items = []

        def pair_node_for_field(name, value):
            return nodes.Pair(nodes.Const(name, lineno=lineno),
                              nodes.Const(value, lineno=lineno),
                              lineno=lineno)

        for f in dataclasses.fields(component_class):
            if f.default is not MISSING:
                items.append(pair_node_for_field(f.name, f.default))
            elif f.default_factory is not MISSING:
                # TODO here we could use `Call` node as the assigning expression
                items.append(pair_node_for_field(f.name, f.default_factory()))

        component_dict = nodes.Dict(items, lineno=lineno)

        # `Assign` dictionary to the "component" name
        return nodes.Assign(nodes.Name(TMP_COMPONENT_DICT_NAME,
                                       'store',
                                       lineno=lineno),
                            component_dict,
                            lineno=lineno)
Exemplo n.º 12
0
 def _parse_profile_block(self, parser, label, source, body, lineno):
     profile_id = self._create_profile_id(parser)
     ret = (
         [
             nodes.Assign(
                 nodes.Name(profile_id, "store").set_lineno(lineno),
                 self.call_method(
                     "_profile_start",
                     dyn_args=nodes.List([label, nodes.Const(source)]).set_lineno(
                         lineno
                     ),
                 ).set_lineno(lineno),
             ).set_lineno(lineno),
         ]
         + body
         + [
             nodes.ExprStmt(
                 self.call_method(
                     "_profile_end", dyn_args=nodes.Name(profile_id, "load")
                 ),
             ).set_lineno(lineno),
         ]
     )
     return ret
 def output(self, parser, block_call, target, tag_name, lineno):
     if target:
         target_node = nodes.Name(target, 'store', lineno=lineno)
         return nodes.Assign(target_node, block_call, lineno=lineno)
     call = nodes.MarkSafe(block_call, lineno=lineno)
     return nodes.Output([call], lineno=lineno)
Exemplo n.º 14
0
        >>> env.compile_expression('var', undefined_to_none=False)()
        Undefined

        **new in Jinja 2.1**
        """
        parser = Parser(self, source, state='variable')
        try:
            expr = parser.parse_expression()
            if not parser.stream.eos:
                raise TemplateSyntaxError('chunk after expression',
                                          parser.stream.current.lineno, None,
                                          None)
        except TemplateSyntaxError, e:
            e.source = source
            raise e
        body = [nodes.Assign(nodes.Name('result', 'store'), expr, lineno=1)]
        template = self.from_string(nodes.Template(body, lineno=1))
        return TemplateExpression(template, undefined_to_none)

    def join_path(self, template, parent):
        """Join a template with the parent.  By default all the lookups are
        relative to the loader root so this method returns the `template`
        parameter unchanged, but if the paths should be relative to the
        parent template, this function can be used to calculate the real
        template name.

        Subclasses may override this method and implement template path
        joining here.
        """
        return template
Exemplo n.º 15
0
    def parse(self, parser):
        """Parse a translatable tag."""
        lineno = next(parser.stream).lineno
        num_called_num = False

        # find all the variables referenced.  Additionally a variable can be
        # defined in the body of the trans block too, but this is checked at
        # a later state.
        plural_expr = None
        plural_expr_assignment = None
        variables = {}
        while parser.stream.current.type != 'block_end':
            if variables:
                parser.stream.expect('comma')

            # skip colon for python compatibility
            if parser.stream.skip_if('colon'):
                break

            name = parser.stream.expect('name')
            if name.value in variables:
                parser.fail('translatable variable %r defined twice.' %
                            name.value, name.lineno,
                            exc=TemplateAssertionError)

            # expressions
            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')

            if plural_expr is None:
                if isinstance(var, nodes.Call):
                    plural_expr = nodes.Name('_trans', 'load')
                    variables[name.value] = plural_expr
                    plural_expr_assignment = nodes.Assign(
                        nodes.Name('_trans', 'store'), var)
                else:
                    plural_expr = var
                num_called_num = name.value == 'num'

        parser.stream.expect('block_end')

        plural = plural_names = None
        have_plural = False
        referenced = set()

        # now parse until endtrans or pluralize
        singular_names, singular = self._parse_block(parser, True)
        if singular_names:
            referenced.update(singular_names)
            if plural_expr is None:
                plural_expr = nodes.Name(singular_names[0], 'load')
                num_called_num = singular_names[0] == 'num'

        # if we have a pluralize block, we parse that too
        if parser.stream.current.test('name:pluralize'):
            have_plural = True
            next(parser.stream)
            if parser.stream.current.type != 'block_end':
                name = parser.stream.expect('name')
                if name.value not in variables:
                    parser.fail('unknown variable %r for pluralization' %
                                name.value, name.lineno,
                                exc=TemplateAssertionError)
                plural_expr = variables[name.value]
                num_called_num = name.value == 'num'
            parser.stream.expect('block_end')
            plural_names, plural = self._parse_block(parser, False)
            next(parser.stream)
            referenced.update(plural_names)
        else:
            next(parser.stream)

        # register free names as simple name expressions
        for var in referenced:
            if var not in variables:
                variables[var] = nodes.Name(var, 'load')

        if not have_plural:
            plural_expr = None
        elif plural_expr is None:
            parser.fail('pluralize without variables', lineno)

        node = self._make_node(singular, plural, variables, plural_expr,
                               bool(referenced),
                               num_called_num and have_plural)
        node.set_lineno(lineno)
        if plural_expr_assignment is not None:
            return [plural_expr_assignment, node]
        else:
            return node
Exemplo n.º 16
0
    def parse(self, parser):
        """Parse a translatable tag."""
        lineno = next(parser.stream).lineno
        num_called_num = False

        # find all the variables referenced.  Additionally a variable can be
        # defined in the body of the trans block too, but this is checked at
        # a later state.
        plural_expr = None
        plural_expr_assignment = None
        variables = {}
        trimmed = None
        while parser.stream.current.type != "block_end":
            if variables:
                parser.stream.expect("comma")

            # skip colon for python compatibility
            if parser.stream.skip_if("colon"):
                break

            name = parser.stream.expect("name")
            if name.value in variables:
                parser.fail(
                    "translatable variable %r defined twice." % name.value,
                    name.lineno,
                    exc=TemplateAssertionError,
                )

            # expressions
            if parser.stream.current.type == "assign":
                next(parser.stream)
                variables[name.value] = var = parser.parse_expression()
            elif trimmed is None and name.value in ("trimmed", "notrimmed"):
                trimmed = name.value == "trimmed"
                continue
            else:
                variables[name.value] = var = nodes.Name(name.value, "load")

            if plural_expr is None:
                if isinstance(var, nodes.Call):
                    plural_expr = nodes.Name("_trans", "load")
                    variables[name.value] = plural_expr
                    plural_expr_assignment = nodes.Assign(
                        nodes.Name("_trans", "store"), var
                    )
                else:
                    plural_expr = var
                num_called_num = name.value == "num"

        parser.stream.expect("block_end")

        plural = None
        have_plural = False
        referenced = set()

        # now parse until endtrans or pluralize
        singular_names, singular = self._parse_block(parser, True)
        if singular_names:
            referenced.update(singular_names)
            if plural_expr is None:
                plural_expr = nodes.Name(singular_names[0], "load")
                num_called_num = singular_names[0] == "num"

        # if we have a pluralize block, we parse that too
        if parser.stream.current.test("name:pluralize"):
            have_plural = True
            next(parser.stream)
            if parser.stream.current.type != "block_end":
                name = parser.stream.expect("name")
                if name.value not in variables:
                    parser.fail(
                        "unknown variable %r for pluralization" % name.value,
                        name.lineno,
                        exc=TemplateAssertionError,
                    )
                plural_expr = variables[name.value]
                num_called_num = name.value == "num"
            parser.stream.expect("block_end")
            plural_names, plural = self._parse_block(parser, False)
            next(parser.stream)
            referenced.update(plural_names)
        else:
            next(parser.stream)

        # register free names as simple name expressions
        for var in referenced:
            if var not in variables:
                variables[var] = nodes.Name(var, "load")

        if not have_plural:
            plural_expr = None
        elif plural_expr is None:
            parser.fail("pluralize without variables", lineno)

        if trimmed is None:
            trimmed = self.environment.policies["ext.i18n.trimmed"]
        if trimmed:
            singular = self._trim_whitespace(singular)
            if plural:
                plural = self._trim_whitespace(plural)

        node = self._make_node(
            singular,
            plural,
            variables,
            plural_expr,
            bool(referenced),
            num_called_num and have_plural,
        )
        node.set_lineno(lineno)
        if plural_expr_assignment is not None:
            return [plural_expr_assignment, node]
        else:
            return node
Exemplo n.º 17
0
    def parse(self, parser):
        stream = parser.stream

        tag = stream.next()

        # get view name
        if stream.current.test('string'):
            # Need to work around Jinja2 syntax here. Jinja by default acts
            # like Python and concats subsequent strings. In this case
            # though, we want {% url "app.views.post" "1" %} to be treated
            # as view + argument, while still supporting
            # {% url "app.views.post"|filter %}. Essentially, what we do is
            # rather than let ``parser.parse_primary()`` deal with a "string"
            # token, we do so ourselves, and let parse_expression() handle all
            # other cases.
            if stream.look().test('string'):
                token = stream.next()
                viewname = nodes.Const(token.value, lineno=token.lineno)
            else:
                viewname = parser.parse_expression()
        else:
            # parse valid tokens and manually build a string from them
            bits = []
            name_allowed = True
            while True:
                if stream.current.test_any('dot', 'sub', 'colon'):
                    bits.append(stream.next())
                    name_allowed = True
                elif stream.current.test('name') and name_allowed:
                    bits.append(stream.next())
                    name_allowed = False
                else:
                    break
            viewname = nodes.Const("".join([b.value for b in bits]))
            if not bits:
                raise TemplateSyntaxError(
                    "'%s' requires path to view" % tag.value, tag.lineno)

        # get arguments
        args = []
        kwargs = []
        while not stream.current.test_any('block_end', 'name:as'):
            if args or kwargs:
                stream.expect('comma')
            if stream.current.test('name') and stream.look().test('assign'):
                key = nodes.Const(stream.next().value)
                stream.skip()
                value = parser.parse_expression()
                kwargs.append(nodes.Pair(key, value, lineno=key.lineno))
            else:
                args.append(parser.parse_expression())

        def make_call_node(*kw):
            return self.call_method('_reverse',
                                    args=[
                                        viewname,
                                        nodes.List(args),
                                        nodes.Dict(kwargs),
                                        nodes.Name('_current_app', 'load'),
                                    ],
                                    kwargs=kw)

        # if an as-clause is specified, write the result to context...
        if stream.next_if('name:as'):
            var = nodes.Name(stream.expect('name').value, 'store')
            call_node = make_call_node(
                nodes.Keyword('fail', nodes.Const(False)))
            return nodes.Assign(var, call_node)
        # ...otherwise print it out.
        else:
            return nodes.Output([make_call_node()]).set_lineno(tag.lineno)
Exemplo n.º 18
0
        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(
            IF_NODE_FIELDS['test'],  # test
            IF_NODE_FIELDS['body'],  # body
            [],  # elif
Exemplo n.º 19
0
    def _parse_blocktrans(self, parser, lineno):
        with_vars = {}
        count = None
        context = None
        trimmed = False
        as_var = None

        if parser.stream.skip_if('name:trimmed'):
            trimmed = True

        if parser.stream.skip_if('name:asvar'):
            as_var = parser.stream.expect(lexer.TOKEN_NAME)
            as_var = nodes.Name(as_var.value, 'store', lineno=as_var.lineno)

        if parser.stream.skip_if('name:with'):
            while parser.stream.look().type == lexer.TOKEN_ASSIGN:
                token = parser.stream.expect(lexer.TOKEN_NAME)
                key = token.value
                next(parser.stream)
                with_vars[key] = parser.parse_expression(False)

        if parser.stream.skip_if('name:count'):
            name = parser.stream.expect(lexer.TOKEN_NAME).value
            parser.stream.expect(lexer.TOKEN_ASSIGN)
            value = parser.parse_expression(False)
            count = (name, value)

        if parser.stream.skip_if('name:context'):
            context = parser.stream.expect(lexer.TOKEN_STRING).value

        parser.stream.expect(lexer.TOKEN_BLOCK_END)

        body_singular = None
        body = []
        additional_vars = set()
        for token in parser.stream:
            if token is lexer.TOKEN_EOF:
                parser.fail(
                    'unexpected end of template, expected endblocktrans tag')
            if token.type is lexer.TOKEN_DATA:
                body.append(token.value)
            elif token.type is lexer.TOKEN_VARIABLE_BEGIN:
                name = parser.stream.expect(lexer.TOKEN_NAME).value
                if name not in with_vars and (count is None
                                              or count[0] != name):
                    additional_vars.add(name)
                parser.stream.expect(lexer.TOKEN_VARIABLE_END)
                # django converts variables inside the blocktrans tag into
                # "%(var_name)s" format, so we do the same.
                body.append('%({})s'.format(name))
            elif token.type is lexer.TOKEN_BLOCK_BEGIN:
                if body_singular is None and parser.stream.skip_if(
                        'name:plural'):
                    if count is None:
                        parser.fail('used plural without specifying count')
                    parser.stream.expect(lexer.TOKEN_BLOCK_END)
                    body_singular = body
                    body = []
                else:
                    parser.stream.expect('name:endblocktrans')
                    break

        if count is not None and body_singular is None:
            parser.fail('plural form not found')

        trans_vars = [
            nodes.Pair(nodes.Const(key), val, lineno=lineno)
            for key, val in with_vars.items()
        ]

        if count is not None:
            trans_vars.append(
                nodes.Pair(nodes.Const(count[0]), count[1], lineno=lineno))

        trans_vars.extend(
            nodes.Pair(nodes.Const(key),
                       nodes.Name(key, 'load', lineno=lineno),
                       lineno=lineno) for key in additional_vars)

        kwargs = [
            nodes.Keyword('trans_vars',
                          nodes.Dict(trans_vars, lineno=lineno),
                          lineno=lineno)
        ]

        if context is not None:
            kwargs.append(
                nodes.Keyword('context',
                              nodes.Const(context, lineno=lineno),
                              lineno=lineno))
        if count is not None:
            kwargs.append(
                nodes.Keyword('count_var',
                              nodes.Const(count[0], lineno=lineno),
                              lineno=lineno))

        body = ''.join(body)
        if trimmed:
            body = ' '.join(map(lambda s: s.strip(),
                                body.strip().splitlines()))

        if body_singular is not None:
            body_singular = ''.join(body_singular)
            if trimmed:
                body_singular = ' '.join(
                    map(lambda s: s.strip(),
                        body_singular.strip().splitlines()))

        if body_singular is None:
            args = []
        else:
            args = [nodes.TemplateData(body_singular, lineno=lineno)]
        args.append(nodes.TemplateData(body, lineno=lineno))
        call = nodes.MarkSafe(self.call_method('_make_blocktrans', args,
                                               kwargs),
                              lineno=lineno)

        if as_var is None:
            return nodes.Output([call], lineno=lineno)
        else:
            return nodes.Assign(as_var, call)
Exemplo n.º 20
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',
    }
Exemplo n.º 21
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",
    }
Exemplo n.º 22
0
 def parse_set(self):
     lineno = next(self.stream).lineno
     target = self.parse_assign_target()
     self.stream.expect('assign')
     expr = self.parse_tuple()
     return nodes.Assign(target, expr, lineno=lineno)
Exemplo n.º 23
0
 def _set_var(var_name, var_value, lineno):
     target_var = nodes.Name(var_name, 'store', lineno=lineno)
     return nodes.Assign(target_var, var_value, lineno=lineno)
Exemplo n.º 24
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