From 051df10c7b95b735ee53eeb1e9c8de1eb48ead14 Mon Sep 17 00:00:00 2001 From: David Lord Date: Thu, 1 Jun 2023 10:42:27 -0700 Subject: [PATCH] fix check for empty required block (#1858) --- CHANGES.rst | 3 +++ src/jinja2/parser.py | 14 ++++++++------ tests/test_inheritance.py | 36 ++++++++++++++++++++++-------------- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index f609ab34..36db0843 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Version 3.1.3 Unreleased +- Fix compiler error when checking if required blocks in parent templates are + empty. :pr:`1858` + Version 3.1.2 ------------- diff --git a/src/jinja2/parser.py b/src/jinja2/parser.py index cefce2df..12703a97 100644 --- a/src/jinja2/parser.py +++ b/src/jinja2/parser.py @@ -311,12 +311,14 @@ class Parser: # enforce that required blocks only contain whitespace or comments # by asserting that the body, if not empty, is just TemplateData nodes # with whitespace data - if node.required and not all( - isinstance(child, nodes.TemplateData) and child.data.isspace() - for body in node.body - for child in body.nodes # type: ignore - ): - self.fail("Required blocks can only contain comments or whitespace") + if node.required: + for body_node in node.body: + if not isinstance(body_node, nodes.Output) or any( + not isinstance(output_node, nodes.TemplateData) + or not output_node.data.isspace() + for output_node in body_node.nodes + ): + self.fail("Required blocks can only contain comments or whitespace") self.stream.skip_if("name:" + node.name) return node diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py index 0c20d4da..8398f4df 100644 --- a/tests/test_inheritance.py +++ b/tests/test_inheritance.py @@ -287,26 +287,34 @@ class TestInheritance: env = Environment( loader=DictLoader( { - "default": "{% block x required %}data {# #}{% endblock %}", - "default1": "{% block x required %}{% block y %}" - "{% endblock %} {% endblock %}", - "default2": "{% block x required %}{% if true %}" - "{% endif %} {% endblock %}", - "level1": "{% if default %}{% extends default %}" - "{% else %}{% extends 'default' %}{% endif %}" - "{%- block x %}CHILD{% endblock %}", + "empty": "{% block x required %}{% endblock %}", + "blank": "{% block x required %} {# c #}{% endblock %}", + "text": "{% block x required %}data {# c #}{% endblock %}", + "block": "{% block x required %}{% block y %}" + "{% endblock %}{% endblock %}", + "if": "{% block x required %}{% if true %}" + "{% endif %}{% endblock %}", + "top": "{% extends t %}{% block x %}CHILD{% endblock %}", } ) ) - t = env.get_template("level1") + t = env.get_template("top") + assert t.render(t="empty") == "CHILD" + assert t.render(t="blank") == "CHILD" - with pytest.raises( + required_block_check = pytest.raises( TemplateSyntaxError, match="Required blocks can only contain comments or whitespace", - ): - assert t.render(default="default") - assert t.render(default="default2") - assert t.render(default="default3") + ) + + with required_block_check: + t.render(t="text") + + with required_block_check: + t.render(t="block") + + with required_block_check: + t.render(t="if") def test_required_with_scope(self, env): env = Environment( -- 2.47.3