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

Improve support for trailing commas in macro signatures, calls & with statements #1712

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Version 3.2.0

Unreleased

- Add support for trailing commas on macro signatures and with statements. :pr:`1712`


Version 3.1.2
-------------
Expand Down
5 changes: 5 additions & 0 deletions docs/templates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,8 @@ override a macro in a parent template. The following will output
{% macro foo() %}CHILD{% endmacro %}
{% block body %}{{ foo() }}{% endblock %}

.. versionadded:: 3.2.0 Added support for trailing commas in macro signatures


.. _call:

Expand Down Expand Up @@ -1922,6 +1924,9 @@ use the ``set`` tag::
In older versions of Jinja (before 2.9) it was required to enable this
feature with an extension. It's now enabled by default.

.. versionadded:: 3.2.0 Added support for trailing commas in with statements


.. _autoescape-overrides:

Autoescape Overrides
Expand Down
8 changes: 8 additions & 0 deletions src/jinja2/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ def parse_with(self) -> nodes.With:
while self.stream.current.type != "block_end":
if targets:
self.stream.expect("comma")
# support for trailing comma
if self.stream.current.type == "block_end":
break
target = self.parse_assign_target()
target.set_ctx("param")
targets.append(target)
Expand Down Expand Up @@ -406,6 +409,9 @@ def parse_signature(self, node: _MacroCall) -> None:
while self.stream.current.type != "rparen":
if args:
self.stream.expect("comma")
# support for trailing comma
if self.stream.current.type == "rparen":
break
arg = self.parse_assign_target(name_only=True)
arg.set_ctx("param")
if self.stream.skip_if("assign"):
Expand Down Expand Up @@ -747,6 +753,7 @@ def parse_list(self) -> nodes.List:
while self.stream.current.type != "rbracket":
if items:
self.stream.expect("comma")
# support for trailing comma
if self.stream.current.type == "rbracket":
break
items.append(self.parse_expression())
Expand All @@ -759,6 +766,7 @@ def parse_dict(self) -> nodes.Dict:
while self.stream.current.type != "rbrace":
if items:
self.stream.expect("comma")
# support for trailing comma
if self.stream.current.type == "rbrace":
break
key = self.parse_expression()
Expand Down
33 changes: 33 additions & 0 deletions tests/test_core_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,30 @@ def test_caller_undefined(self, env_trim):
)
assert tmpl.render() == "True"

def test_trailing_comma_signature(self, env_trim):
tmpl = env_trim.from_string(
"""\
{% macro m(a, b,) %}{{ a }}|{{ b }}{% endmacro %}
{{ m(1,2) }}"""
)
assert tmpl.render() == "1|2"

def test_trailing_comma_arguments(self, env_trim):
tmpl = env_trim.from_string(
"""\
{% macro m(a, b) %}{{ a }}|{{ b }}{% endmacro %}
{{ m(1,2,) }}"""
)
assert tmpl.render() == "1|2"

def test_trailing_comma_call(self, env_trim):
tmpl = env_trim.from_string(
"""\
{% macro test(a) %}{{ a }}|[[{{ caller() }}]]{% endmacro %}\
{% call test(a=42,) %}data{% endcall %}"""
)
assert tmpl.render() == "42|[[data]]"

def test_include(self, env_trim):
env_trim = Environment(
loader=DictLoader(
Expand Down Expand Up @@ -593,3 +617,12 @@ def test_with_argument_scoping(self, env):
"""
)
assert tmpl.render(b=3, e=4) == "1|2|3|4|5"

def test_with_trailing_comma(self, env):
tmpl = env.from_string(
"""\
{% with a=42, b=23, -%}
{{ a }} = {{ b }}
{% endwith -%}"""
)
assert tmpl.render().strip() == "42 = 23"