Is it possible to have any values accessed by a Jinja2 template treated
by some custom function before it is handed to the template?  This
should work regardless of how the value is accessed so the function
should be applied to the global variables of the template as well all of
the properties of elements of those variables.

A bit of a simplistic example, but in essence I would like to be able to
do the following:

    environment = …
    environment.set_value_wrapper(
        lambda x: 'fourtytwo' if x == 42 else x)
    rendered = env.from_string("""
        {{ foo }}
        {{ bar.baz }}
        {% for i in qux %} {{ i }} {% endfor %}
    """).render({
        'foo': 42,
        'bar': { 'baz': 42 },
        'qux': [ 42, 24 ]
    })
    
    assert rendered == """
        fourtytwo
        fourtytwo
         fourtytwo 24
    """

At the moment I'm using quite a convoluted environment class with
a custom template_class and a proxy for context:

    class _ContextProxy(jinja2.runtime.Context):
      def __init__(self, ctx):
          self._ctx = ctx
    
      def resolve(self, key):
          return self._ctx.environment._wrap_value(self._ctx.resolve(key))
    
      def __getattr__(self, name):
          return getattr(self._ctx, name)

    class _Environment(jinja2.Environment):

      class template_class(jinja2.Template):
          def new_context(self, *args, **kw):
              ctx = super(_Environment.template_class, self).new_context(
                  *args, **kw)
              return _ContextProxy(ctx)
    
      def getitem(self, obj, name):
          obj = super(_Environment, self).getitem(obj, name)
          return self._wrap_value(obj)
    
      def getattr(self, obj, name):
          obj = super(_Environment, self).getattr(obj, name)
          return obj if name == 'tiid' else self._wrap_value(obj)
    
      def _wrap_value(self, obj):
        # … do stuff to obj
        if isinstance(obj, (list, tuple)):
            # So that deconstruction and for loops work correctly.
            obj = type(obj)(self._wrap_value(v) for v in obj)
        return obj

This kinda works but is fragile and looks like a lot of code to
achieve a rather simple effect (or so one would think).

Note that having some custom auto-escaping function is not sufficient
because in actual code I need to transform a certain object into an
object of a different kind.

I also do not want to do this beforehand because the _wrap_value is
relatively expensive and the object I need to wrap may also be a result
of a function call.

-- 
Best regards,                                         _     _
.o. | Liege of Serenely Enlightened Majesty of      o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz    (o o)
ooo +--<[email protected]>--<xmpp:[email protected]>--ooO--(_)--Ooo--

-- 
You received this message because you are subscribed to the Google Groups 
"pocoo-libs" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/pocoo-libs.
For more options, visit https://groups.google.com/d/optout.

Reply via email to