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

Prevent random filter from being folded #734

Merged
merged 4 commits into from Jul 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES
Expand Up @@ -22,6 +22,10 @@ Version 2.10
- Added a `trimmed` modifier to `{% trans %}` to strip linebreaks and
surrounding whitespace. Also added a new policy to enable this for all
`trans` blocks.
- The ``random`` filter is no longer incorrectly constant folded and will
produce a new random choice each time the template is rendered. (`#478`_)

.. _#478: https://github.com/pallets/jinja/pull/478

Version 2.9.6
-------------
Expand Down
10 changes: 5 additions & 5 deletions jinja2/filters.py
Expand Up @@ -10,8 +10,8 @@
"""
import re
import math
import random

from random import choice
from itertools import groupby
from collections import namedtuple
from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \
Expand Down Expand Up @@ -359,13 +359,13 @@ def do_last(environment, seq):
return environment.undefined('No last item, sequence was empty.')


@environmentfilter
def do_random(environment, seq):
@contextfilter
def do_random(context, seq):
"""Return a random item from the sequence."""
try:
return choice(seq)
return random.choice(seq)
except IndexError:
return environment.undefined('No random item, sequence was empty.')
return context.environment.undefined('No random item, sequence was empty.')


def do_filesizeformat(value, binary=False):
Expand Down
21 changes: 16 additions & 5 deletions tests/test_filters.py
Expand Up @@ -8,6 +8,7 @@
:copyright: (c) 2017 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
import random
import pytest
from jinja2 import Markup, Environment
from jinja2._compat import text_type, implements_to_string
Expand Down Expand Up @@ -182,11 +183,21 @@ def test_pprint(self, env):
data = list(range(1000))
assert tmpl.render(data=data) == pformat(data)

def test_random(self, env):
tmpl = env.from_string('''{{ seq|random }}''')
seq = list(range(100))
for _ in range(10):
assert int(tmpl.render(seq=seq)) in seq
def test_random(self, env, request):
# restore the random state when the test ends
state = random.getstate()
request.addfinalizer(lambda: random.setstate(state))
# generate the random values from a known seed
random.seed('jinja')
expected = [random.choice('1234567890') for _ in range(10)]

# check that the random sequence is generated again by a template
# ensures that filter result is not constant folded
random.seed('jinja')
t = env.from_string('{{ "1234567890"|random }}')

for value in expected:
assert t.render() == value

def test_reverse(self, env):
tmpl = env.from_string('{{ "foobar"|reverse|join }}|'
Expand Down