[Welcome] [TitleIndex] [WordIndex

Problem

You like Quixote PTL, but need a simple templating mechanism such that non-programmers can manipulate text or html without being exposed to Python or PTL. Cheetah and other templating mechanisms offer wonderful power, but perhaps more than you really need or want, and often such power comes with a performance cost.

Inspired by a post from Andrew Kuchling on switching to Cheetah from PTL, I had a play with Cheetah and found it very flexible indeed, but I wondered if for my own purposes I could use a simpler mechanism and still take advantage of PTL and its advantages. My goal n this was to enable non programmers to create simple on-disk html (or any text format - email notification messsages for example) templates. No logic is available within the templates - that's all expected to be done in the application, where some feel it belongs.

Solution

The shiny new and barely tested Quixote SimpleTemplate. If all one needs is simple variable replacement, and no exotic features such as looping or access to all of python from within the template itself, this may be for you. My need was a way to inject "chunks" of text or htmltext, generated by PTL callables, into an html or text on-disk template.

Automatic escaping of the 'namespace' is really the key - anything not already escaped or explicitly marked as htmltext will be escaped -- this approach is both convenient and safe, as it forces the programmer to be explicit about what will not be escaped. This again fits into the PTL philosophy too.

   1 import string
   2 from quixote.html import htmlescape, htmltext
   3 
   4 def _escape_namespace(namespace):
   5     """(namespace : mapping) -> a new htmlescaped escaped mapping
   6     """
   7     D = {}
   8     for k, v in namespace.items():
   9         D[k] = htmlescape(v)
  10     return D
  11 
  12 def format_text(text, namespace, html=True, raise_errors=True):
  13     """(text:basestring, namespace:mapping, 
  14         [html:boolean, raise_errors:boolean]) -> htmltext | text
  15     
  16     Performs simple string.Template replacement of $placeholder values.
  17 
  18     Note: If html is True, a copy of namespace will be made and all
  19           values will be htmlescaped (htmlescape is smart and won't
  20           double escape any already htmlescaped instances).
  21 
  22     See also: string.Template for restrictions on what placeholder 
  23           values may be. Stick to simple strings and you'll be ok, 
  24           eg:
  25              $one is ok
  26              $1 is not
  27     """
  28     if html:
  29         namespace = _escape_namespace(namespace)
  30     if raise_errors: 
  31         result = string.Template(text).substitute(namespace)
  32     else:
  33         # safe_sub should really be called unsafe_substitute !
  34         result = string.Template(text).safe_substitute(namespace)
  35     return html and htmltext(result) or result
  36 

Example

   1 from random import choice
   2 
   3 def menumaker [html]():
   4     '\n<ul>\n'
   5     for n in range(5):
   6         '<li>%s with %s</li>\n' % (
   7             choice(['eggs','fish','burgers', 
   8                     'rancid cheese', 'pigeon', 
   9                     'souvlaki','crunchy frog']),
  10             choice(['plum sauce', 'spam', 
  11                      'a lovely bunch of coconuts',
  12                      'cream sauce', 'fries','rice']))
  13     '</ul>\n'
  14 
  15 def my_page():
  16     # the "template" could of course be read from a file...
  17     htmltemplate = """
  18       <html>
  19       <title>$title</title>
  20       <body>
  21       <p>Today's menu is:</p>
  22       $menu
  23       </body>
  24       </html>"""
  25     
  26     namespace = {'title':">> Monty Python's Employee Cafe <<",
  27                  'menu':menumaker()}
  28     print format_text(htmltemplate, namespace)
  29 

Returns something like:

<html>
  <title>&gt;&gt; Monty Python's Employee Cafe &lt;&lt;</title>
<body>
  <p>Today's menu is:</p>
  <ul>
    <li>eggs with spam</li>
    <li>pigeon with cream sauce</li>
    <li>eggs with spam</li>
    <li>crunchy frog with pork rinds</li>
    <li>rancid cheese with cream sauce</li>
  </ul>
</body>
</html>

Note the title was automatically escaped because it was not explicitly identified as htmltext or previously htmlescape'd.

I imagine using simple templates such as shown, in combination with PTL, with its sane approach to escaping that which is not explicitly maked "safe", could be used to good effect.

- MikeWatkins

Discussion

Comments welcome - what have I missed?- MikeWatkins

You've missed pointing out that string.Template is the new shell-style string-formatting mechanism. I've had similar idea with the old style, e.g.  "<!-- %(blah)s -->" % {'blah':'bleh'} .

Recently, I've had the problem of trying to use cheetah to template postscript, as exported from xfig. This works surprisingly well, if one remembers these two rules:

1. No images, just xfig drawing. If you need an eps logo, or whatever, fix the template by hand or by using .replace().

2. Make the remaining dollars map to themselves:

Lastly, I need to ask: Is it just me or are the rules for $ in cheetah just dumb?

>>> from Cheetah.Template import T       
>>> t = T(source="here's an example of double-dollar: $$. Wow, how dumb.")
>>> str(t)
"here's an example of double-dollar: $$. Wow, how dumb."

- AndersEurenius

CategoryCookbook


2010-09-22 22:14