Writing custom Chameleon expression

26 views
Skip to first unread message

Thierry Florac

unread,
Jan 27, 2015, 5:17:33 AM1/27/15
to pylons-...@googlegroups.com
Hi,

Based on Chameleon documentation, I'm trying to write a custom "provider:" TALES expression which will allow to load another content provider template, based on a registered named adapter.
The code is as follow:

class ProviderExpression(object):
    """provider: TALES expression"""

    def __init__(self, expression):
        self.expression = expression

    def __call__(self, target, engine):
        request = get_current_request()
        registry = request.registry
        provider = registry.queryMultiAdapter((request.context, request, request.annotations['view']),
                                              IContentProvider, name=self.expression)
        if provider is None:
            raise ContentProviderLookupError(self.expression)
        provider.update()
        value = ast.Str(provider.render())
        return [ast.Assign(targets=[target], value=value)]

PageTemplateFile.expression_types['provider'] = ProviderExpression

My problem with this is simple: when the main template is loaded for the first time, everything is OK. But afterwards, the output of the content provider is cached and the dynamic elements are not executed anymore!
What is the way to handle this?

Best regards,
Thierry

Theron Luhn

unread,
Feb 7, 2015, 2:29:59 PM2/7/15
to pylons-...@googlegroups.com
A bit late to the party, but hopefully not too late to be helpful.  I don't know a whole lot about customizing Chameleon like this, but I'll do my best to answer.

As you may already know, Chameleon renders each template into Python bytecode.  So what your function is doing is generating an AST which is compiled into the template bytecode.

Let's say provider.render() returns "foo".  The first time the template is called, your expression will end up as bytecode equivalent to "target = 'foo'"  The next time the template is called, the previously generated bytecode is run.  So no matter what "provider.render()" might return this time, all the template is doing is running "target = 'foo'".

What you need to do is break off the code to grab the provider and render it into its own function, then have your ProviderExpression returning the AST for running that function, i.e. the equivalent of "target = render_provider()".  I have limited experience with Python's AST, so unfortunately I can't advise you on how to achieve that.

Anyways, I'm not quite sure what your use case is, but extending Chameleon seems a bit extreme.  In my opinion, a simple Python function (executed via tal:condition="myfunc()") or Chameleon's macros would work best for most situations.

Theron Luhn

unread,
Feb 7, 2015, 2:37:37 PM2/7/15
to pylons-...@googlegroups.com
Correction: that tal statement should be "tal:content="myfunc()""

--
You received this message because you are subscribed to a topic in the Google Groups "pylons-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/pylons-discuss/AnsMKuRd-vQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to pylons-discus...@googlegroups.com.
To post to this group, send email to pylons-...@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages