[Templates] Re: TT in Python
Sean McAfee
eefacm@gmail.com
Wed, 4 Apr 2007 12:27:21 -0700
------=_Part_11094_5455717.1175714841630
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
On 4/3/07, Darren Chamberlain <dlc@sevenroot.org> wrote:
>
> On 4/3/07, Sean McAfee <eefacm@gmail.com> wrote:
> > So, not much interest has been expressed in my proposal so far--not
> > surprisingly, since I imagine this audience doesn't include many regular
> > Python users. I wish I wasn't one myself. However, I still think a
> Python
> > implementation for the Template Toolkit would be a great thing to
> have. The
> > TT's power blows away any Python templating system I've ever
> encountered.
>
> I started a Python port of TT about three, maybe four years ago. Andy
> and I discussed hosting it alongside the Perl source tree, but I
> didn't get very far with it.
>
> You didn't mention what you're using to generate the Template.Grammar
> class,
Actually, I took the fast/lazy route of translating Template::Grammar
directly. A few regexen handled the state transition tables, while I
handled the rule routines manually.
but I took the approach of starting with the Perl grammar
> (parser/Parser.yp), modifying the productions to be Python instead of
> Perl, and then making a Grammar.py.skel to hold the code. I
> considered using something other than YAPP to build the grammar, but
> keeping the grammar the same between two different parser generators
> wasn't something I wanted to think about, and I liked being able to
> compare the Perl and Python versions side by side and see the exact
> differences. All the native Python parser generators I saw did all
> their work at runtime, and I think building a static grammar module
> (the way Template::Grammar is built) is the Right Way to do it; The
> TT grammar is not small, and building it dynamically when the grammar
> module is loaded seems very wasteful to me. (Python is slow enough as
> it is!) As far as generating the grammar statically: The problem is
> the whitespace. Normally it doesn't bother me (I can even see how it
> could be construed as a feature), but it makes generating Python code
> artificially difficult.
This actually turned out to be far less difficult than I expected, with the
aid of a code-building helper class. For example, from the directive
routine to build an "if" statement:
code = Code()
code.write("if %s:" % expr, code.indent, block)
for expr, block in elses:
code.write(code.unindent, "elif %s:" % expr, code.indent, block)
if else_ is not None:
code.write(code.unindent, "else:", code.indent, else_)
return code.text()
Furthermore, all of the indentation-sensitive code lives in the Python
version of Directive.pm. I didn't need to care about indentation at all
when translating Grammar.pm.
I think there would have been a definite niche for it a few years ago,
> but at this point there are a few template libraries for Python that
> are popular, and usable, if not ideal. I don't use Python much
> anymore, myself, so I can't say that I would need to use it now, but I
> would have killed for a complete TT implementation in Python a few
> years ago (I was part of a team that built a massive Zope product a
> few years ago, and I lost much time and sanity to ZPT, but I've done
> very little with Python since then).
Seems reasonable that there are people who would kill for one now, then,
right? Aside from myself, that is.
Has you gotten opinions on this
> from anyone in the python community? Are there any prospective users?
Well, I use Python because I have to, not because I want to (although I like
it better now than I did at the start), so I haven't really become a part of
the Python community-at-large. What I had in mind was more along the lines
of: Throw another template system into the mix, and may the best one win, or
at least prosper. It's hard for me to imagine the TT wouldn't do well. I
mean, consider Django, seemingly one of the more popular options out there.
The template language is severely underwhelming compared to the TT. To do
something like a switch, you have to do this:
{% ifequal x 1 %}
...
{% else %}
{% ifequal x 2 %}
...
{% else %}
{% ifequal x 3 %}
...
{% endifequal %}
{% endifequal %}
{% endifequal %}
Some actual code at my workplace has one of these beasts seven levels deep,
because there's no better way to do it. Who wouldn't jump at the
opportunity to use something cleaner and more powerful? Or take
Clearsilver. You can't even do something as simple as pass an array
directly to your renderer. Where with the TT you do this:
$template->process($file, { rows => \@rows });
With CS, you need to populate a "hierarchical data format" object, indexing
your data purely with strings. It looks kind of like this:
my $hdf = HDF->new();
for my $i (0 .. $#rows) {
$hdf->setValue("row.$i", $rows[$i]);
}
$renderer->render($hdf);
Repeat for every array in the dataset. Just painful.
--Sean
------=_Part_11094_5455717.1175714841630
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
On 4/3/07, <b class="gmail_sendername">Darren Chamberlain</b> <<a href="mailto:dlc@sevenroot.org">dlc@sevenroot.org</a>> wrote:<div><span class="gmail_quote"></span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
On 4/3/07, Sean McAfee <<a href="mailto:eefacm@gmail.com">eefacm@gmail.com</a>> wrote:<br>> So, not much interest has been expressed in my proposal so far--not<br>> surprisingly, since I imagine this audience doesn't include many regular
<br>> Python users. I wish I wasn't one myself. However, I still think a Python<br>> implementation for the Template Toolkit would be a great thing to have. The<br>> TT's power blows away any Python templating system I've ever encountered.
<br><br>I started a Python port of TT about three, maybe four years ago. Andy<br>and I discussed hosting it alongside the Perl source tree, but I<br>didn't get very far with it.<br><br>You didn't mention what you're using to generate the
Template.Grammar<br>class,</blockquote><div><br>
Actually, I took the fast/lazy route of translating Template::Grammar
directly. A few regexen handled the state transition tables,
while I handled the rule routines manually.<br>
</div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">but I took the approach of starting with the Perl grammar<br>(parser/Parser.yp), modifying the productions to be Python instead of
<br>Perl, and then making a Grammar.py.skel to hold the code. I<br>considered using something other than YAPP to build the grammar, but<br>keeping the grammar the same between two different parser generators<br>wasn't something I wanted to think about, and I liked being able to
<br>compare the Perl and Python versions side by side and see the exact<br>differences. All the native Python parser generators I saw did all<br>their work at runtime, and I think building a static grammar module<br>(the way Template::Grammar is built) is the Right Way to do it; The
<br>TT grammar is not small, and building it dynamically when the grammar<br>module is loaded seems very wasteful to me. (Python is slow enough as<br>it is!) As far as generating the grammar statically: The problem is<br>
the whitespace. Normally it doesn't bother me (I can even see how it<br>could be construed as a feature), but it makes generating Python code<br>artificially difficult.</blockquote><div><br>
This actually turned out to be far less difficult than I expected, with
the aid of a code-building helper class. For example, from the
directive routine to build an "if" statement:<br>
<br>
<span style="font-family: courier new,monospace;">code = Code()</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">code.write("if %s:" % expr, code.indent, block)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">for expr, block in elses:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> code.write(code.unindent, "elif %s:" % expr, code.indent, block)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">if else_ is not None:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> code.write(code.unindent, "else:", code.indent, else_)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">return code.text()</span><br>
<br>
Furthermore, all of the indentation-sensitive code lives in the Python
version of <a href="http://Directive.pm">Directive.pm</a>. I didn't need to care about indentation
at all when translating <a href="http://Grammar.pm">Grammar.pm</a>.<br>
</div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">I think there would have been a definite niche for it a few years ago,<br>but at this point there are a few template libraries for Python that
<br>are popular, and usable, if not ideal. I don't use Python much<br>anymore, myself, so I can't say that I would need to use it now, but I<br>would have killed for a complete TT implementation in Python a few<br>
years ago (I was part of a team that built a massive Zope product a<br>few years ago, and I lost much time and sanity to ZPT, but I've done<br>very little with Python since then).</blockquote><div><br>
Seems reasonable that there are people who would kill for one now, then, right? Aside from myself, that is.<br>
</div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Has you gotten opinions on this<br>from anyone in the python community? Are there any prospective users?
</blockquote><div><br>
Well, I use Python because I have to, not because I want to (although I
like it better now than I did at the start), so I haven't really become
a part of the Python community-at-large. What I had in mind was
more along the lines of: Throw another template system into the mix,
and may the best one win, or at least prosper. It's hard for me
to imagine the TT wouldn't do well. I mean, consider Django,
seemingly one of the more popular options out there. The template
language is severely underwhelming compared to the TT. To do
something like a switch, you have to do this:<br>
<br>
<span style="font-family: courier new,monospace;">{% ifequal x 1 %}</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">...</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">{% else %}</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">{% ifequal x 2 %}</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">...</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">{% else %}</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">{% ifequal x 3 %}</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">...</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">{% endifequal %}</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">{% endifequal %}</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">{% endifequal %}</span><br>
<br>
Some actual code at my workplace has one of these beasts seven levels
deep, because there's no better way to do it. Who wouldn't jump
at the opportunity to use something cleaner and more powerful? Or
take Clearsilver. You can't even do something as simple as pass
an array directly to your renderer. Where with the TT you do this:<br>
<br>
<span style="font-family: courier new,monospace;">$template->process($file, { rows => \@rows });</span><br>
<br>
With CS, you need to populate a "hierarchical data format" object,
indexing your data purely with strings. It looks kind of like
this:<br>
<br>
<span style="font-family: courier new,monospace;">my $hdf = HDF->new();</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">for my $i (0 .. $#rows) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> $hdf->setValue("row.$i", $rows[$i]);</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">}</span><br>
<span style="font-family: courier new,monospace;">$renderer->render($hdf);</span><br>
<br>
Repeat for every array in the dataset. Just painful.<br>
<br>
<br>
--Sean<br>
</div></div>
------=_Part_11094_5455717.1175714841630--