Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trying to use an iterator as a section fails after the first time #182

Open
bdesham opened this issue Jan 27, 2016 · 0 comments
Open

Trying to use an iterator as a section fails after the first time #182

bdesham opened this issue Jan 27, 2016 · 0 comments

Comments

@bdesham
Copy link

bdesham commented Jan 27, 2016

Consider the following simple use of Pystache under Python 3:

import pystache

context = {
    'numbers': [
        {'number': 1},
        {'number': 2},
        {'number': 3}
    ]
}

template = '''
    {{ #numbers }}
    * {{ number }}
    {{ /numbers }}

    {{ #numbers }}
    * {{ number }}
    {{ /numbers }}
'''

def double(item):
    item['number'] *= 2
    return item

context['numbers'] = map(double, context['numbers'])

renderer = pystache.Renderer()
print(renderer.render(pystache.parse(template), context))

The expected output is, modulo whitespace,

* 2
* 4
* 6

* 2
* 4
* 6

But the actual output is just

* 2
* 4
* 6

The problem is that context['numbers'] is an iterator, not an ordinary list. Once we’ve iterated through it once, its items are “used up” and so it acts like an empty list on subsequent iterations. I’d argue that this is a bug—rendering a Mustache template shouldn’t ever alter the context.

In the meantime, you can get around this bug by manually converting the iterator to a list. In the example above, using the line

context['numbers'] = list(map(double, context['numbers']))

gives the expected output.

(I tried to fix this by changing part of RenderEngine.fetch_section_data:

try:
    iter(data)
except TypeError:
    # Then the value does not support iteration.
    data = [data]
else:
    if is_string(data) or isinstance(data, dict):
        # Do not treat strings and dicts (which are iterable) as lists.
        data = [data]
    else:
        # Otherwise, treat the value as a list.  We call list() on it
        # in case it's a generator--if we didn't do this then iterating
        # through it once would "use up" all of the values and trying
        # to iterate a second time would produce nothing.
        data = list(data)

but that didn’t do it. I think the call to list() needs to be made somewhere earlier in the call stack.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant