pystache
pystache copied to clipboard
Renderer.context won't update when looping through an array
My target: print the following lines:
Al,John,Jack
Tim,Tom,Todd
without a final comma.
I tried this way:
ctx = {
'gangs': [
{'gangsters': [ {'name': 'Al' }, {'name': 'John'}, {'name': 'Jack'}]},
{'gangsters': [ {'name': 'Tim'}, {'name': 'Tom'} , {'name': 'Todd'}]},
]
}
class Lambdas(object):
def __init__(self, renderer):
self.renderer = renderer
def rstrip(self):
"Remove last character"
print self.renderer.context
return lambda s: self.renderer.render(s, self.renderer.context)[:-1]
renderer = pystache.Renderer(missing_tags='strict')
print renderer.render("""
{{#gangs}}
{{#rstrip}}{{#gangsters}}{{name}},{{/gangsters}}{{/rstrip}}
{{/gangs}}
""", ctx, Lambdas(renderer))
The output:
ContextStack({'gangs': [{'gangsters': [{'name': 'Al'}, {'name': 'John'}, {'name': 'Jack'}]}, {'gangsters': [{'name': 'Tim'}, {'name': 'Tom'}, {'name': 'Todd'}]}]}, <__main__.Lambdas object at 0x15cadb10>, {'gangsters': [{'name': 'Al'}, {'name': 'John'}, {'name': 'Jack'}]})
ContextStack({'gangs': [{'gangsters': [{'name': 'Al'}, {'name': 'John'}, {'name': 'Jack'}]}, {'gangsters': [{'name': 'Tim'}, {'name': 'Tom'}, {'name': 'Todd'}]}]}, <__main__.Lambdas object at 0x15cadb10>, {'gangsters': [{'name': 'Al'}, {'name': 'John'}, {'name': 'Jack'}]})
Al,John,Jack
Al,John,Jack
The culprit is the invocation to render() inside rstrip. Notice how, during the second call, the 3d element of the ContextStack is exactly identical to the previous call, instead of changing to {'gangsters': [ {'name': 'Tim'}, {'name': 'Tom'} , {'name': 'Todd'}]}.
Is this a bug, or am I missing something?!?
Rewriting it as dicts won't work either:
ctx = {
'gang1': { 'gangsters': [ {'name': 'Al' }, {'name': 'John'}, {'name': 'Jack'}] },
'gang2': { 'gangsters': [ {'name': 'Tim'}, {'name': 'Tom'} , {'name': 'Todd'}] }
}
print renderer.render("""
{{#gang1}}
{{#rstrip}}{{#gangsters}}{{name}},{{/gangsters}}{{/rstrip}}
{{/gang1}}
{{#gang2}}
{{#rstrip}}{{#gangsters}}{{name}},{{/gangsters}}{{/rstrip}}
{{/gang2}}
""", ctx, Lambdas(renderer))
Yes, it looks like there may be an issue. I will try to track this down.
It looks like the issue is that calling self.renderer.render() inside the lambda has the side effect of overwriting the renderer's original context property with a new context stack. Later calls to self.renderer.context then no longer reference the original context which has the right gang.
This is related to this TODO.
One work-around is to avoid changing the original renderer's context by creating a new renderer each time:
def rstrip(self):
"Remove last character"
print self.renderer.context
renderer = pystache.Renderer(missing_tags='strict')
return lambda s: renderer.render(s, self.renderer.context)[:-1]
Another work-around is to make sure you're always referencing the original context:
class Lambdas(object):
def __init__(self, renderer):
self.renderer = renderer
self.context = None
def rstrip(self):
"Remove last character"
if self.context is None:
self.context = self.renderer.context
print self.renderer.context
return lambda s: self.renderer.render(s, self.context)[:-1]
I think issue #157 is related and may have other suggestions.
Thanks, this works fine:
def rstrip(self):
"Remove last character"
return lambda s: copy.deepcopy(self.renderer).render(s, self.renderer.context)[:-1]