No inline control statements?

927 views
Skip to first unread message

ru...@yahoo.com

unread,
Jan 6, 2013, 7:23:28 PM1/6/13
to mako-d...@googlegroups.com
Hello,

I'm currently trying to decide between Mako and Jinja2.  A big plus for Mako (for me) is being able to use Python in the template rather than Jinja's psuedo-python.

The big downside (for me) with Mako is the lack of in-line control statements (i.e. the need to put "%if" on a separate line).

Something I find I often need to do is conditionally insert the value of a variable with some associate text.  As an example, I want to print a place name followed by a date in parens if 'date' has a value, but followed by nothing if 'date' is None.  Note that I am generating plain text, not white-space-compressing html.  The following works:

(1)
  import mako, mako.template
  t = mako.template.Template('''\
  Filed: ${place}${' ('+date+')' if date else ''}\
  ''')

  place = "Boston"
  date = '2012-01-06'
  print (t.render (**locals()))

  date = None
  print (t.render (**locals()))

But....  I really don't like having what should be template text (the parens) dynamically generated by python code (and real-world code is more complicated).  What I want do is write a template like:

(2)
  t = mako.template.Template('''\
  Filed: ${place}%if date (${date})%endif\
  ''')

but of course that doesn't work.  In the following

(3)
  t = mako.template.Template('''\
  Filed: ${place}
  %if date:
   [${date}]
  %endif\
  ''')

the date comes out on a separate line and there is an extraneous newline at the end.

How can I generate the output of (1) while getting closest to the template form of (2)(best) or (3)(ok) with Mako?

Apologies if this is an excessively trivial question but I did spend quite a bit of time reading the documentation and experimenting without finding a good answer.

Michael Bayer

unread,
Jan 6, 2013, 8:16:51 PM1/6/13
to mako-d...@googlegroups.com
On Jan 6, 2013, at 7:23 PM, ru...@yahoo.com wrote:

(1)
  import mako, mako.template
  t = mako.template.Template('''\
  Filed: ${place}${' ('+date+')' if date else ''}\
  ''')

  place = "Boston"
  date = '2012-01-06'
  print (t.render (**locals()))

  date = None
  print (t.render (**locals()))

But....  I really don't like having what should be template text (the parens) dynamically generated by python code (and real-world code is more complicated).  What I want do is write a template like:

(2)
  t = mako.template.Template('''\
  Filed: ${place}%if date (${date})%endif\
  ''')

Regarding the question of "control lines that take up only one line", first addressing it from the perspective of not having to add more newlines to the template source than is necessary.  As I got to your issue #3 I realized you might be concerned about output only, which we have covered already so just skip to the bottom for that, but since I put all this thought in already for the other case, here's that too.  

For non-newline control statements, the issue is that parsing in Mako is gets involved in situations when we're essentially scanning along Python and have to figure out "where the Python ends".   Issues like quoting and such, for example, and a : can appear inside a dictionary literal too.    In the case of control statements, the newline is a pretty big anchor for us.   Patches here would need to be proposed for lexer.py: 


parsing a ternary if / else would likely be it's own parse target (like def match_ternary_statement()), since it's pretty different than a traditional control line.   In which case we might as well pick a great syntax for it.   But then I checked the aforementioned jinja2.   For a ternary, they don't seem to do any better than us:   http://jinja.pocoo.org/docs/templates/#if-expression  as you can see the HTML is quoted there as an expression too.

However, if the case is that Jinja2's (% if <expr> %}, because it has a closing %} allows it to be inlined like {% if <expr> %} <html> {% else %} <html> {% endif %}, then I'd want to think a bit bigger here.   I'd want to go into match_control_line() as we did and just find some way to make the newline optional:

% if <expr>:\n
    <html>\n
% else:\n
   <html>\n
% endif\n

we could perhaps just co-opt the { } verbosity:

{% if <expr>:}  <html> {% else:} <html> {% endif}

or just rip them off totally:

{% if <expr> %}  <html> {% else %} <html> {% endif %}

either of the above would require a rewritten (either in-place or additional version of) match_control_line(), as we'd be doing the same kind of matching which we do in match_expression(), which is that we need to make use of parse_until_text() so that we properly skip over anything that might be Python code.     I'd want the two formats to be completely interchangeable:

% if expr:
<html> {% else %} <html> 
% endif

{% if <expr> %} <html>
% elif <expr>:
<html>
% else:
<html> {% endif %}

just some ideas but I'd need someone to be motivated to help patch out lexer.py and add new tests as well.

but of course that doesn't work.  In the following

(3)
  t = mako.template.Template('''\
  Filed: ${place}
  %if date:
   [${date}]
  %endif\
  ''')

the date comes out on a separate line and there is an extraneous newline at the end.

Ok this seems like an entirely different question, you're not as much concerned about newlines in the template as you are in the output, so in this case you need to use the backslash to escape out the newline that's after [$(date)], and note that since we're in a Python literal in this context (not a template file) you need two slashes:

from mako.template import Template

t = Template('''\
    Filed: ${place}\\
    % if date:
        [${date}]\\
    % endif
''')

print t.render(place="place", date="Tuesday")


output:

$ python test.py
    Filed: place        [Tuesday]
$





ru...@yahoo.com

unread,
Jan 7, 2013, 12:14:16 PM1/7/13
to mako-d...@googlegroups.com
On Sunday, January 6, 2013 6:16:51 PM UTC-7, Michael Bayer wrote:
[responding to the last point first...]

> Ok this seems like an entirely different question, you're not as much concerned about newlines in the template as you are in the output,

It wasn't clear in my own thinking when I posted, but yes, I guess I was really asking two different questions.   Getting the right output is highest priority of course, so thanks for that answer.  I should have thought to try doubling the backslashes myself.  I wonder if the use of doubled backslashes to concatenate content separated by control statements should be mentioned in the documentation?  (Or did I miss it?)

> Regarding the question of "control lines that take up only one line"...

Thanks very much for the detailed answer.  I think the ability is important because without it one has to build up horizontal content by adding vertical content to the template.  ISTM that one of the big benefits of using templates is the template approximates what the output will look like, and that benefit is compromised by the need to put template items that are part of the same output line, on different lines.

While it's too bad to learn there isn't any way to do that now, your willingness to consider a suitable patch is very encouraging.  I thought its lack might be due to ideological issues.

Reply all
Reply to author
Forward
0 new messages