Question

Can one compile or revert a portion of the Jinja2 AST?

For example, is it possible to call a function or method from jinja2.environment or jinja2.compiler.generate or some equivalent on a list of nodes extracted from within a template?

For example, given a template y.html:

avant-tag
{% xyz %}
tag content {{ 3 + 5 }}
{% endxyz %}
apres-tag

and an extension y.py:

# -*- coding: utf-8 -*-
from jinja2 import nodes, Environment, FileSystemLoader
from jinja2.ext import Extension

class YExtension(Extension):
    tags = set(['y'])

    def __init__(self, environment):
        super(YExtension, self).__init__(environment)

    def parse(self, parser):
        tag = parser.stream.next()
        body = parser.parse_statements(['name:endy'], drop_needle=True)
        return nodes.Const("<!-- slurping: %s -->" % str(body))

env = Environment(
    loader      = FileSystemLoader('.'),
    extensions  = [YExtension],
    )

print env.get_template('x.html').render()

Running python y.py results in the expected output of:

avant-tag
 <!-- slurping: [Output(nodes=[TemplateData(data=u'\n    tag-content '),
   Add(left=Const(value=3), right=Const(value=5)),
   TemplateData(data=u'\n ')])] -->
sous-tag

In the parse method, how can one either:

  1. compile body to unicode (i.e. tag-content 8); or, alternatively
  2. revert body to its original source (i.e. tag-content {{ 3 + 5 }}).

As a matter of background, this question relates to two prior questions:

  1. Jinja2 compile extension after includes; and
  2. Insert javascript at top of including file in Jinja 2

Thank you for reading.

Brian

Was it helpful?

Solution

Compiling to unicode is not yet possible in the parse() method since you don't have the context available at that point. You can hack around it ofcourse but it would probably not be the best way to go.

Note that the parse() step is normally only executed once on a html file, after that it will use the parsed bytecode to render the template. The results of the parse step can be rendered given an environment.

You simply don't have the context available there, and getting the context in there... quite difficult ;)

To get the original source however... not much easier without hacking, but the hacking isn't too bad ;)

class YExtension(Extension):
    tags = set(['y'])

    def preprocess(self, source, name, filename=None):
        # insert some code here that replaces '{% xyz %}foo bar{% endxyz %}'
        # with something like: '{% xyz %}foo bar{% raw %}foo bar{% endraw %}{% endxyz %}'
        return source

After that you can read the text as the value from the {% raw %} node. Be sure to trash it after that or it will show in your template.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top