Skip to content

Commit

Permalink
Merge branch 'master' into NATIVE_TYPES
Browse files Browse the repository at this point in the history
  • Loading branch information
davidism committed Oct 31, 2017
2 parents 68820c3 + 31f92b5 commit 6a7a263
Show file tree
Hide file tree
Showing 13 changed files with 56 additions and 22 deletions.
21 changes: 18 additions & 3 deletions CHANGES
Expand Up @@ -24,9 +24,9 @@ Version 2.10
`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`_)
- Add a ``unique`` filter. (`#469`_)
- Add ``min`` and ``max`` filters. (`#475`_)
- Add tests for all comparison operators: ``eq``, ``ne``, ``lt``, ``le``,
- Added a ``unique`` filter. (`#469`_)
- Added ``min`` and ``max`` filters. (`#475`_)
- Added tests for all comparison operators: ``eq``, ``ne``, ``lt``, ``le``,
``gt``, ``ge``. (`#665`_)
- ``import`` statement cannot end with a trailing comma. (`#617`_, `#618`_)
- ``indent`` filter will not indent blank lines by default. (`#685`_)
Expand All @@ -44,6 +44,21 @@ Version 2.10
.. _#692: https://github.com/pallets/jinja/pull/692
.. _#708: https://github.com/pallets/jinja/pull/708

Version 2.9.7
-------------

(bugfix release, in development)

- ``tojson`` filter marks output as safe to match documented behavior.
(`#718`_)
- Resolved a bug where getting debug locals for tracebacks could
modify template context.
- Fixed a bug where having many `{% elif ... %}` blocks resulted in a
"too many levels of indentation" error. These blocks now compile to
native `elif ..:` instead of `else: if ..:` (#759)

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

Version 2.9.6
-------------
(bugfix release, released on April 3rd 2017)
Expand Down
7 changes: 7 additions & 0 deletions jinja2/compiler.py
Expand Up @@ -1159,6 +1159,13 @@ def visit_If(self, node, frame):
self.indent()
self.blockvisit(node.body, if_frame)
self.outdent()
for elif_ in node.elif_:
self.writeline('elif ', elif_)
self.visit(elif_.test, if_frame)
self.write(':')
self.indent()
self.blockvisit(elif_.body, if_frame)
self.outdent()
if node.else_:
self.writeline('else:')
self.indent()
Expand Down
2 changes: 1 addition & 1 deletion jinja2/debug.py
Expand Up @@ -198,7 +198,7 @@ def translate_exception(exc_info, initial_skip=0):
def get_jinja_locals(real_locals):
ctx = real_locals.get('context')
if ctx:
locals = ctx.get_all()
locals = ctx.get_all().copy()
else:
locals = {}

Expand Down
2 changes: 1 addition & 1 deletion jinja2/environment.py
Expand Up @@ -809,7 +809,7 @@ def _load_template(self, name, globals):
@internalcode
def get_template(self, name, parent=None, globals=None):
"""Load a template from the loader. If a loader is configured this
method ask the loader for the template and returns a :class:`Template`.
method asks the loader for the template and returns a :class:`Template`.
If the `parent` parameter is not `None`, :meth:`join_path` is called
to get the real template name before loading.
Expand Down
2 changes: 1 addition & 1 deletion jinja2/filters.py
Expand Up @@ -339,7 +339,7 @@ def do_min(environment, value, case_sensitive=False, attribute=None):

@environmentfilter
def do_max(environment, value, case_sensitive=False, attribute=None):
"""Return the smallest item from the sequence.
"""Return the largest item from the sequence.
.. sourcecode:: jinja
Expand Down
3 changes: 2 additions & 1 deletion jinja2/idtracking.py
Expand Up @@ -231,9 +231,10 @@ def inner_visit(nodes):
return rv

body_symbols = inner_visit(node.body)
elif_symbols = inner_visit(node.elif_)
else_symbols = inner_visit(node.else_ or ())

self.symbols.branch_update([body_symbols, else_symbols])
self.symbols.branch_update([body_symbols, elif_symbols, else_symbols])

def visit_Macro(self, node, **kwargs):
self.symbols.store(node.name)
Expand Down
2 changes: 1 addition & 1 deletion jinja2/nodes.py
Expand Up @@ -314,7 +314,7 @@ class For(Stmt):

class If(Stmt):
"""If `test` is true, `body` is rendered, else `else_`."""
fields = ('test', 'body', 'else_')
fields = ('test', 'body', 'elif_', 'else_')


class Macro(Stmt):
Expand Down
13 changes: 6 additions & 7 deletions jinja2/parser.py
Expand Up @@ -210,17 +210,16 @@ def parse_if(self):
node.test = self.parse_tuple(with_condexpr=False)
node.body = self.parse_statements(('name:elif', 'name:else',
'name:endif'))
node.elif_ = []
node.else_ = []
token = next(self.stream)
if token.test('name:elif'):
new_node = nodes.If(lineno=self.stream.current.lineno)
node.else_ = [new_node]
node = new_node
node = nodes.If(lineno=self.stream.current.lineno)
result.elif_.append(node)
continue
elif token.test('name:else'):
node.else_ = self.parse_statements(('name:endif',),
drop_needle=True)
else:
node.else_ = []
result.else_ = self.parse_statements(('name:endif',),
drop_needle=True)
break
return result

Expand Down
2 changes: 1 addition & 1 deletion jinja2/utils.py
Expand Up @@ -567,7 +567,7 @@ def htmlsafe_json_dumps(obj, dumper=None, **kwargs):
.replace(u'>', u'\\u003e') \
.replace(u'&', u'\\u0026') \
.replace(u"'", u'\\u0027')
return rv
return Markup(rv)


@implements_iterator
Expand Down
9 changes: 9 additions & 0 deletions tests/test_core_tags.py
Expand Up @@ -249,6 +249,15 @@ def test_elif(self, env):
%}...{% else %}XXX{% endif %}''')
assert tmpl.render() == '...'

def test_elif_deep(self, env):
elifs = '\n'.join('{{% elif a == {0} %}}{0}'.format(i)
for i in range(1, 1000))
tmpl = env.from_string('{{% if a == 0 %}}0{0}{{% else %}}x{{% endif %}}'
.format(elifs))
for x in (0, 10, 999):
assert tmpl.render(a=x).strip() == str(x)
assert tmpl.render(a=1000).strip() == 'x'

def test_else(self, env):
tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}')
assert tmpl.render() == '...'
Expand Down
5 changes: 3 additions & 2 deletions tests/test_filters.py
Expand Up @@ -640,8 +640,9 @@ def __init__(self, id, name):
def test_json_dump(self):
env = Environment(autoescape=True)
t = env.from_string('{{ x|tojson }}')
assert t.render(x={'foo': 'bar'}) == '{"foo": "bar"}'
assert t.render(x='"bar\'') == r'"\"bar\u0027"'
assert t.render(x={'foo': 'bar'}) == '{"foo": "bar"}'
assert t.render(x='"ba&r\'') == r'"\"ba\u0026r\u0027"'
assert t.render(x='<bar>') == r'"\u003cbar\u003e"'

def my_dumps(value, **options):
assert options == {'foo': 'bar'}
Expand Down
8 changes: 4 additions & 4 deletions tests/test_idtracking.py
Expand Up @@ -61,7 +61,7 @@ def test_complex():
nodes.Output([
nodes.Name('title_upper', 'load'),
nodes.Call(nodes.Name('render_title', 'load'), [
nodes.Const('Aha')], [], None, None)])], [])])])
nodes.Const('Aha')], [], None, None)])], [], [])])])

for_loop = nodes.For(
nodes.Name('item', 'store'),
Expand Down Expand Up @@ -155,7 +155,7 @@ def test_if_branching_stores():
tmpl = nodes.Template([
nodes.If(nodes.Name('expression', 'load'), [
nodes.Assign(nodes.Name('variable', 'store'),
nodes.Const(42))], [])])
nodes.Const(42))], [], [])])

sym = symbols_for_node(tmpl)
assert sym.refs == {
Expand All @@ -177,7 +177,7 @@ def test_if_branching_stores_undefined():
nodes.Assign(nodes.Name('variable', 'store'), nodes.Const(23)),
nodes.If(nodes.Name('expression', 'load'), [
nodes.Assign(nodes.Name('variable', 'store'),
nodes.Const(42))], [])])
nodes.Const(42))], [], [])])

sym = symbols_for_node(tmpl)
assert sym.refs == {
Expand All @@ -197,7 +197,7 @@ def test_if_branching_stores_undefined():
def test_if_branching_multi_scope():
for_loop = nodes.For(nodes.Name('item', 'store'), nodes.Name('seq', 'load'), [
nodes.If(nodes.Name('expression', 'load'), [
nodes.Assign(nodes.Name('x', 'store'), nodes.Const(42))], []),
nodes.Assign(nodes.Name('x', 'store'), nodes.Const(42))], [], []),
nodes.Include(nodes.Const('helper.html'), True, False)
], [], None, False)

Expand Down
2 changes: 2 additions & 0 deletions tox.ini
Expand Up @@ -34,6 +34,8 @@ passenv = CI TRAVIS TRAVIS_*
deps = codecov
skip_install = true
commands =
# install argparse for 2.6
python -c 'import sys, pip; sys.version_info < (2, 7) and pip.main(["install", "argparse", "-q"])'
coverage combine
coverage report
codecov

0 comments on commit 6a7a263

Please sign in to comment.