3

In Jinja2, is it possible to have a Node from the AST render after all include statements have completed?

This is a key piece of a solution to a bigger puzzle.

Example code:

x.py

from jinja2 import nodes, Environment, FileSystemLoader
from jinja2.ext import Extension

class XExtension(Extension):
    tags = set(['x', 'get_x'])

    def __init__(self, environment):
        super(XExtension, self).__init__(environment)
        environment.extend(
            x = 0,
        )

    def parse(self, parser):
        tag = parser.stream.next()
        return getattr(self, "_%s" % str(tag))(parser, tag)

   def _get_x(self, parser, tag):
        """ Return the output """
        return nodes.Const(self.environment.x)

   def _x(self, parser, tag):
        """ Add an x """
        self.environment.x += 1
        return nodes.Const('<!-- Adding an X -->')

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

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

x.html

Xx {% x %} Xx {% x %}
{% include "y.html" %}
Xs xes: {% get_x %}

y.html

Yx {% x %}
Ys xes: {% get_x %}

The output is

Xx <!-- Adding an X --> Xx <!-- Adding an X -->
Yx <!-- Adding an X -->
Ys xes:3
Xs xes 2

How may it be possible to have Xs xes count the X's in y.html, which is the behaviour I desire and expect?

In other words, is there a way to delay the parsing or flattening to text returned from the _get_x() in x.html?

Thank you very much for reading.

Kind regards,

Brian

Community
  • 1
  • 1
Brian M. Hunt
  • 81,008
  • 74
  • 230
  • 343
  • It was a good idea separating this into another question, the first one was getting rather long ;-) – Cameron Nov 28 '10 at 01:21

1 Answers1

3

Jinja2 does streaming of template data. The template is evaluated instruction for instruction into a stream of smaller strings that gets concatenated into an actual unicode string by the render() method. However you can also get hold of the stream by calling into generate() instead of render().

With some in-band signalling and postprocessing of the stream one might probably be able to implement something like that, but it's against the way of how Jinja2 was designed so it might break horribly and is totally unsupported.

Armin Ronacher
  • 31,998
  • 13
  • 65
  • 69
  • Thank you for the reply. It may be of assistance if I were able to `jinja2.compiler.generator` or equivalently process a list of `Output` nodes to unicode (i.e. nodes not encapsulated in a `Template` node) -- I'd be grateful to know if there is a straightforward way to do this. – Brian M. Hunt Nov 28 '10 at 02:25
  • Not sure I understand. I think if you want to continue go down that road, the Environment callback functions for streaming and pre/postprocessing are probably more of a help than the actual compiler interface. The reason for this is that what you try to do has to happen on a different level than the compilation which has to undergo certain rules. – Armin Ronacher Nov 28 '10 at 16:29
  • Thanks, Armin. I have an extension that extracts nodes, and I wish to save those nodes to the current environment, then render them into unicode after the current template completes rendering. What I seek is along the lines of a function like `Environment.render(nodes) -> unicode` where `nodes` is a list of (non-Template) nodes slurped by the extension and saved to the Environment. Alternatively, I would like to either save the rendered nodes to the environment during processing, or convert them back to source to be rendered independently. – Brian M. Hunt Nov 29 '10 at 00:26
  • I've opened a new question, that I hope clarifies the issue: http://stackoverflow.com/questions/4309266 – Brian M. Hunt Nov 29 '10 at 23:50