From 7a19fbe112b231f90f08c89d4776999317308649 Mon Sep 17 00:00:00 2001 From: Hai Zhu <35182391+cocolato@users.noreply.github.com> Date: Tue, 6 Feb 2024 08:19:24 -0500 Subject: [PATCH] Fix the unexpected error that occurs when an empty control block is used. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/sqlalchemy/mako/issues/146 When the first control block is empty or comment, the correct result will now be rendered. ```python from mako.template import Template template = r""" % if False: % elif False: % else: test % endif """ t = Template(template) print(t.render()) ``` Result: ``` test ``` Closes: #387 Pull-request: https://github.com/sqlalchemy/mako/pull/387 Pull-request-sha: fb257ff866148a79bfe58ccaf7c98f499f8d8424 Change-Id: Ief78cdf4eb39b6e8257332ed034dab052c715420 --- doc/build/unreleased/146.rst | 8 ++++ mako/codegen.py | 26 +++++++++---- test/test_template.py | 71 ++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 doc/build/unreleased/146.rst diff --git a/doc/build/unreleased/146.rst b/doc/build/unreleased/146.rst new file mode 100644 index 00000000..85ec87a8 --- /dev/null +++ b/doc/build/unreleased/146.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: bug, codegen + :tickets: 146 + + Fixed unexpected error when use control lines which the + first control block with no bodies other than comments, + as `pass` is now added to the first empty block. + Pull request courtesy Hai Zhu. diff --git a/mako/codegen.py b/mako/codegen.py index ce6f83aa..b9fea937 100644 --- a/mako/codegen.py +++ b/mako/codegen.py @@ -838,13 +838,24 @@ def visitControlLine(self, node): text = node.text self.printer.writeline(text) children = node.get_children() - # this covers the three situations where we want to insert a pass: - # 1) a ternary control line with no children, - # 2) a primary control line with nothing but its own ternary - # and end control lines, and - # 3) any control line with no content other than comments - if not children or ( - all( + + # this covers the four situations where we want to insert a pass: + # 1) a ternary control line with no children, + # 2) a primary control line with nothing but its own ternary + # and end control lines, and + # 3) any control line with no content other than comments + # 4) the first control block with no content other than comments + def _search_for_control_line(): + for c in children: + if isinstance(c, parsetree.Comment): + continue + elif isinstance(c, parsetree.ControlLine): + return True + return False + + if ( + not children + or all( isinstance(c, (parsetree.Comment, parsetree.ControlLine)) for c in children ) @@ -853,6 +864,7 @@ def visitControlLine(self, node): for c in children if isinstance(c, parsetree.ControlLine) ) + or _search_for_control_line() ): self.printer.writeline("pass") diff --git a/test/test_template.py b/test/test_template.py index e03415e2..cd7d89e5 100644 --- a/test/test_template.py +++ b/test/test_template.py @@ -1036,6 +1036,47 @@ def test_blank_control_8(self): template_args={"ctx": ctx}, ) + def test_blank_control_9(self): + self._do_memory_test( + """ + % if True: + % elif False: + false + % else: + broken + % endif + """, + "", + filters=lambda s: s.strip(), + template_args={"ctx": ctx}, + ) + + def test_blank_control_10(self): + self._do_memory_test( + """ + % if True: + % else: + test + % endif + """, + "", + filters=lambda s: s.strip(), + template_args={"ctx": ctx}, + ) + + def test_blank_control_11(self): + self._do_memory_test( + """ + % try: + % except: + error + % endtry + """, + "", + filters=lambda s: s.strip(), + template_args={"ctx": ctx}, + ) + def test_commented_blank_control_1(self): self._do_memory_test( """ @@ -1135,6 +1176,36 @@ def test_commented_blank_control_8(self): template_args={"ctx": ctx}, ) + def test_commented_blank_control_9(self): + self._do_memory_test( + """ + % if True: + ## comment + % elif False: + false + % else: + broken + % endif + """, + "", + filters=lambda s: s.strip(), + template_args={"ctx": ctx}, + ) + + def test_commented_blank_control_10(self): + self._do_memory_test( + """ + % try: + ## comment + % except: + error + % endtry + """, + "", + filters=lambda s: s.strip(), + template_args={"ctx": ctx}, + ) + def test_multiline_control(self): t = Template( """