Skip to content

Commit

Permalink
- [feature] Control lines with no bodies will
Browse files Browse the repository at this point in the history
  now succeed, as "pass" is added for these
  when no statements are otherwise present.
  Courtesy Ben Trofatter [ticket:146]
  • Loading branch information
zzzeek committed Apr 3, 2012
1 parent f75834b commit 1b4d1fb
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 7 deletions.
6 changes: 6 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
0.7.1
- [feature] Control lines with no bodies will
now succeed, as "pass" is added for these
when no statements are otherwise present.
Courtesy Ben Trofatter [ticket:146]

0.7.0
- [feature] Added new "loop" variable to templates,
is provided within a % for block to provide
Expand Down
2 changes: 1 addition & 1 deletion mako/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
# the MIT License: http://www.opensource.org/licenses/mit-license.php


__version__ = '0.7.0'
__version__ = '0.7.1'

13 changes: 11 additions & 2 deletions mako/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,6 @@ def visitExpression(self, node):

def visitControlLine(self, node):
if node.isend:
if not node.get_children():
self.printer.writeline("pass")
self.printer.writeline(None)
if node.has_loop_context:
self.printer.writeline('finally:')
Expand All @@ -779,6 +777,17 @@ def visitControlLine(self, node):
else:
text = node.text
self.printer.writeline(text)
children = node.get_children()
# this covers the two situations where we want to insert a pass:
# 1) a ternary control line with no children and
# 2) a primary control line with nothing but its own ternary
# and end control lines
if (not node.get_children or
util.all(isinstance(c, parsetree.ControlLine)
for c in children) and
util.all((node.is_ternary(c.keyword) or c.isend)
for c in children)):
self.printer.writeline("pass")

def visitText(self, node):
self.write_source_comment(node)
Expand Down
17 changes: 15 additions & 2 deletions mako/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def __init__(self, text, filename=None,
self.match_position = 0
self.tag = []
self.control_line = []
self.ternary_stack = []
self.disable_unicode = disable_unicode
self.encoding = input_encoding

Expand Down Expand Up @@ -134,18 +135,30 @@ def append_node(self, nodecls, *args, **kwargs):
self.template.nodes.append(node)
# build a set of child nodes for the control line
# (used for loop variable detection)
# also build a set of child nodes on ternary control lines
# (used for determining if a pass needs to be auto-inserted
if self.control_line:
self.control_line[-1].nodes.append(node)
control_frame = self.control_line[-1]
control_frame.nodes.append(node)
if not (isinstance(node, parsetree.ControlLine) and
control_frame.is_ternary(node.keyword)):
if self.ternary_stack and self.ternary_stack[-1]:
self.ternary_stack[-1][-1].nodes.append(node)
if isinstance(node, parsetree.Tag):
if len(self.tag):
node.parent = self.tag[-1]
self.tag.append(node)
elif isinstance(node, parsetree.ControlLine):
if node.isend:
self.control_line.pop()
self.ternary_stack.pop()
elif node.is_primary:
self.control_line.append(node)
elif len(self.control_line) and \
self.ternary_stack.append([])
elif self.control_line and \
self.control_line[-1].is_ternary(node.keyword):
self.ternary_stack[-1].append(node)
elif self.control_line and \
not self.control_line[-1].is_ternary(node.keyword):
raise exceptions.SyntaxException(
"Keyword '%s' not a legal ternary for keyword '%s'" %
Expand Down
11 changes: 10 additions & 1 deletion mako/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
time_func = time.clock
else:
time_func = time.time

def function_named(fn, name):
"""Return a function with a given __name__.
Expand All @@ -57,15 +57,24 @@ def newfunc(*fargs, **fkeywords):
return newfunc

if py24:
def all(iterable):
for i in iterable:
if not i:
return False
return True

def exception_name(exc):
try:
return exc.__class__.__name__
except AttributeError:
return exc.__name__
else:
all = all

def exception_name(exc):
return exc.__class__.__name__


class PluginLoader(object):
def __init__(self, group):
self.group = group
Expand Down
77 changes: 76 additions & 1 deletion test/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ def test_control(self):
"yes x has test"
]

def test_blank_control(self):
def test_blank_control_1(self):
self._do_memory_test(
"""
% if True:
Expand All @@ -808,6 +808,81 @@ def test_blank_control(self):
filters=lambda s:s.strip()
)

def test_blank_control_2(self):
self._do_memory_test(
"""
% if True:
% elif True:
% endif
""",
"",
filters=lambda s:s.strip()
)

def test_blank_control_3(self):
self._do_memory_test(
"""
% if True:
% else:
% endif
""",
"",
filters=lambda s:s.strip()
)

def test_blank_control_4(self):
self._do_memory_test(
"""
% if True:
% elif True:
% else:
% endif
""",
"",
filters=lambda s:s.strip()
)

def test_blank_control_5(self):
self._do_memory_test(
"""
% for x in range(10):
% endfor
""",
"",
filters=lambda s:s.strip()
)

def test_blank_control_6(self):
self._do_memory_test(
"""
% while False:
% endwhile
""",
"",
filters=lambda s:s.strip()
)

def test_blank_control_7(self):
self._do_memory_test(
"""
% try:
% except:
% endtry
""",
"",
filters=lambda s:s.strip()
)

def test_blank_control_8(self):
self._do_memory_test(
"""
% with open('x', 'w') as fp:
% endwith
""",
"",
filters=lambda s:s.strip()
)

def test_multiline_control(self):
t = Template("""
% for x in \\
Expand Down

0 comments on commit 1b4d1fb

Please sign in to comment.