*. The expression should evaluate
to a number or string that is a valid interval (e.g., 0.5, '3m', etc).
To refresh whenever an expression is true, use test=EXPRESSION. The
expression can be a method/function returning true or false, a boolean
placeholder, several of these joined by and and/or or, or any other
expression. If the expression contains spaces, it's easier to read if
you enclose it in (), but this is not required.
To refresh whenever you say so, use id=EXPRESSION. Your program can
then call .refreshCache(ID) whenever it wishes. This is useful if the
cache depends on some external condition that changes infrequently but
has just changed now.
You can combine arguments by separating them with commas. For
instance, you can specify both id= and interval=, or id= and test=.
(You can also combine interval and test although it's not very
useful.) However, repeating an argument is undefined.
#cache
This is a static cache. It will not be refreshed.
$a $b $c
#end cache
#cache timer='30m', id='cache1'
#for $cust in $customers
$cust.name:
$cust.street - $cust.city
#end for
#end cache
#cache id='sidebar', test=$isDBUpdated
... left sidebar HTML ...
#end cache
#cache id='sidebar2', test=($isDBUpdated or $someOtherCondition)
... right sidebar HTML ...
#end cache
The #cache directive cannot be nested.
We are planning to add a 'varyBy' keyword argument in the future that
will allow a separate cache instances to be created for a variety of
conditions, such as different query string parameters or browser
types. This is inspired by ASP.net's varyByParam and varyByBrowser
output caching keywords.
7.5 #raw
Syntax:
#raw
#end raw
Any section of a template definition that is inside a #raw ... #end
raw tag pair will be printed verbatim without any parsing of
$placeholders or other directives. This can be very useful for
debugging, or for Cheetah examples and tutorials.
#raw is conceptually similar to HTML's tag and LaTeX's
verbatim{} tag, but unlike those tags, #raw does not cause the body to
appear in a special font or typeface. It can't, because Cheetah
doesn't know what a font is.
7.6 #include
Syntax:
#include [raw] FILENAME_EXPR
#include [raw] source=STRING_EXPR
The #include directive is used to include text from outside the
template definition. The text can come from an external file or from a
$placeholder variable. When working with external files, Cheetah will
monitor for changes to the included file and update as necessary.
This example demonstrates its use with external files:
#include "includeFileName.txt"
The content of "includeFileName.txt" will be parsed for Cheetah
syntax.
And this example demonstrates use with $placeholder variables:
#include source=$myParseText
The value of $myParseText will be parsed for Cheetah syntax. This is
not the same as simply placing the $placeholder tag ``$myParseText''
in the template definition. In the latter case, the value of
$myParseText would not be parsed.
By default, included text will be parsed for Cheetah tags. The
argument ``raw'' can be used to suppress the parsing.
#include raw "includeFileName.txt"
#include raw source=$myParseText
Cheetah wraps each chunk of #include text inside a nested Template
object. Each nested template has a copy of the main template's
searchList. However, #set variables are visible across includes only
if the defined using the #set global keyword.
All directives must be balanced in the include file. That is, if you
start a #for or #if block inside the include, you must end it in the
same include. (This is unlike PHP, which allows unbalanced constructs
in include files.)
7.7 #slurp
Syntax:
#slurp
The #slurp directive eats up the trailing newline on the line it
appears in, joining the following line onto the current line.
It is particularly useful in #for loops:
#for $i in range(5)
$i #slurp
#end for
outputs:
0 1 2 3 4
7.8 #indent
This directive is not implemented yet. When/if it's completed, it will
allow you to
1. indent your template definition in a natural way (e.g., the bodies
of #if blocks) without affecting the output
2. add indentation to output lines without encoding it literally in
the template definition. This will make it easier to use Cheetah
to produce indented source code programmatically (e.g., Java or
Python source code).
There is some experimental code that recognizes the #indent directive
with options, but the options are purposely undocumented at this time.
So pretend it doesn't exist. If you have a use for this feature and
would like to see it implemented sooner rather than later, let us know
on the mailing list.
The latest specification for the future #indent directive is in the
TODO file in the Cheetah source distribution.
7.9 Ouput Filtering and #filter
Syntax:
#filter FILTER_CLASS_NAME
#filter $PLACEHOLDER_TO_A_FILTER_INSTANCE
#filter None
Output from $placeholders is passed through an ouput filter. The
default filter merely returns a string representation of the
placeholder value, unless the value is None, in which case the filter
returns an empty string. Only top-level placeholders invoke the
filter; placeholders inside expressions do not.
Certain filters take optional arguments to modify their behaviour. To
pass arguments, use the long placeholder syntax and precede each
filter argument by a comma. By convention, filter arguments don't take
a $ prefix, to avoid clutter in the placeholder tag which already has
plenty of dollar signs. For instance, the MaxLen filter takes an
argument 'maxlen':
${placeholderName, maxlen=20}
${functionCall($functionArg), maxlen=$myMaxLen}
To change the output filter, use the 'filter' keyword to the Template
class constructor, or the #filter directive at runtime (details
below). You may use #filter as often as you wish to switch between
several filters, if certain $placeholders need one filter and other
$placeholders need another.
The standard filters are in the module Cheetah.Filters. Cheetah
currently provides:
Filter
The default filter, which converts None to '' and everything
else to str(whateverItIs). This is the base class for all other
filters, and the minimum behaviour for all filters distributed
with Cheetah.
ReplaceNone
Same.
MaxLen
Same, but truncate the value if it's longer than a certain
length. Use the 'maxlen' filter argument to specify the length,
as in the examples above. If you don't specify 'maxlen', the
value will not be truncated.
Pager
Output a "pageful" of a long string. After the page, output
HTML hyperlinks to the previous and next pages. This filter
uses several filter arguments and environmental variables,
which have not been documented yet.
WebSafe
Same as default, but convert HTML-sensitive characters (' $<$
', '&', ' $>$ ') to HTML entities so that the browser will
display them literally rather than interpreting them as HTML
tags. This is useful with database values or user input that
may contain sensitive characters. But if your values contain
embedded HTML tags you want to preserve, you do not want this
filter.
The filter argument 'also' may be used to specify additional
characters to escape. For instance, say you want to ensure a
value displays all on one line. Escape all spaces in the value
with ' ', the non-breaking space:
${$country, also=' '}}
To switch filters using a class object, pass the class using the
filter argument to the Template constructor, or via a placeholder to
the #filter directive: #filter $myFilterClass. The class must be a
subclass of Cheetah.Filters.Filter. When passing a class object, the
value of filtersLib does not matter, and it does not matter where the
class was defined.
To switch filters by name, pass the name of the class as a string
using the filter argument to the Template constructor, or as a bare
word (without quotes) to the #filter directive: #filter TheFilter. The
class will be looked up in the filtersLib.
The filtersLib is a module containing filter classes, by default
Cheetah.Filters. All classes in the module that are subclasses of
Cheetah.Filters.Filter are considered filters. If your filters are in
another module, pass the module object as the filtersLib argument to
the Template constructor.
Writing a custom filter is easy: just override the .filter method.
def filter(self, val, **kw): # Returns a string.
Return the string that should be output for `val'. `val' may be any
type. Most filters return `' for None. Cheetah passes one keyword
argument: kw['rawExpr'] is the placeholder name as it appears in the
template definition, including all subscripts and arguments. If you
use the long placeholder syntax, any options you pass appear as
keyword arguments. Again, the return value must be a string.
You can always switch back to the default filter this way: #filter
None. This is easy to remember because "no filter" means the default
filter, and because None happens to be the only object the default
filter treats specially.
We are considering additional filters; see
http://webware.colorstudy.net/twiki/bin/view/Cheetah/MoreFiltersfor
the latest ideas.
8 Import, Inheritance, Declaration and Assignment
8.1 #import and #from directives
Syntax:
#import MODULE_OR_OBJECT [as NAME] [, ...]
#from MODULE import MODULE_OR_OBJECT [as NAME] [, ...]
The #import and #from directives are used to make external Python
modules or objects available to placeholders. The syntax is identical
to the import syntax in Python. Imported modules are visible globally
to all methods in the generated Python class.
#import math
#import math as mathModule
#from math import sin, cos
#from math import sin as _sin
#import random, re
#from mx import DateTime # ## Part of Egenix's mx package.
After the above imports, $math, $mathModule, $sin, $cos and $_sin,
$random, $re and $DateTime may be used in $placeholders and
expressions.
8.2 #extends
Syntax:
#extends CLASS
All templates are subclasses of Cheetah.Template.Template. However,
it's possible for a template to subclass another template or a pure
Python class. This is where #extends steps in: it specifies the parent
class. It's equivalent to PSP's ``@page extends='' directive.
Cheetah imports the class mentioned in an #extends directive
automatically if you haven't imported it yet. The implicit importing
works like this:
#extends Superclass
## Implicitly does '#from Superclass import Superclass'.
#extends Cheetah.Templates.SkeletonPage
## Implicitly does '#from Cheetah.Templates.SkeletonPage import SkeletonPage'.
If your superclass is in an unusual location or in a module named
differently than the class, you must import it explicitly. There is no
support for extending from a class that is not imported; e.g., from a
template dynamically created from a string. Since the most practical
way to get a parent template into a module is to precompile it, all
parent templates essentially have to be precompiled.
There can be only one #extends directive in a template and it may list
only one class. In other words, templates don't do multiple
inheritance. This is intentional: it's too hard to initialize multiple
base classes correctly from inside a template. However, you can do
multiple inheritance in your pure Python classes.
If your pure Python class overrides any of the standard Template
methods such as .__init__ or .awake, be sure to call the superclass
method in your method or things will break. Examples of calling the
superclass method are in section 13.4. A list of all superclass
methods is in section 13.5.
In all cases, the root superclass must be Template. If your bottommost
class is a template, simply omit the #extends in it and it will
automatically inherit from Template. If your bottommost class is a
pure Python class, it must inherit from Template explicitly:
from Cheetah.Template import Template
class MyPurePythonClass(Template):
If you're not keen about having your Python classes inherit from
Template, create a tiny glue class that inherits both from your class
and from Template.
Before giving any examples we'll stress that Cheetah does not dictate
how you should structure your inheritance tree. As long as you follow
the rules above, many structures are possible.
Here's an example for a large web site that has not only a general
site template, but also a template for this section of the site, and
then a specific template-servlet for each URL. (This is the
``inheritance approach'' discussed in the Webware chapter.) Each
template inherits from a pure Python class that contains
methods/attributes used by the template. We'll begin with the
bottommost superclass and end with the specific template-servlet:
1. SiteLogic.py (pure Python class containing methods for the site)
from Cheetah.Template import Template
class SiteLogic(Template):
2. Site.tmpl/py (template containing the general site framework;
this is the template that controls the output,
the one that contains "...", the one
that contains text outside any #def/#block.)
#from SiteLogic import SiteLogic
#extends SiteLogic
#implements respond
3. SectionLogic.py (pure Python class with helper code for the section)
from Site import Site
class SectionLogic(Site)
4. Section.tmpl/py (template with '#def' overrides etc. for the section)
#from SectionLogic import SectionLogic
#extends SectionLogic
5. page1Logic.py (pure Python class with helper code for the template-servlet
)
from Section import Section
class indexLogic(Section):
6. page1.tmpl/py (template-servlet for a certain page on the site)
#from page1Logic import page1Logic
#extends page1Logic
A pure Python classes might also contain methods/attributes that
aren't used by their immediate child template, but are available for
any descendant template to use if it wishes. For instance, the site
template might have attributes for the name and e-mail address of the
site administrator, ready to use as $placeholders in any template that
wants it.
Whenever you use #extends, you often need #implements too, as in step
2 above. Read the next section to understand what #implements is and
when to use it.
8.3 #implements
Syntax:
#implements METHOD
You can call any #def or #block method directly and get its outpt. The
top-level content - all the text/placeholders/directives outside any
#def/#block - gets concatenated and wrapped in a ``main method'', by
default .respond(). So if you call .respond(), you get the ``whole
template output''. When Webware calls .respond(), that's what it's
doing. And when you do 'print t' or 'str(t)' on a template instance,
you're taking advantage of the fact that Cheetah makes .__str__() an
alias for the main method.
That's all fine and dandy, but what if your application prefers to
call another method name rather than .respond()? What if it wants to
call, say, .send_output() instead? That's where #implements steps in.
It lets you choose the name for the main method. Just put this in your
template definition:
#implements send_output
When one template extends another, every template in the inheritance
chain has its own main method. To fill the template, you invoke
exactly one of these methods and the others are ignored. The method
you call may be in any of the templates in the inheritance chain: the
base template, the leaf template, or any in between, depending on how
you structure your application. So you have two problems: (1) calling
the right method name, and (2) preventing an undesired same-name
subclass method from overriding the one you want to call.
Cheetah assumes the method you will call is .respond() because that's
what Webware calls. It further assumes the desired main method is the
one in the lowest-level base template, because that works well with
#block as described in the Inheritance Approach for building Webware
servlets (section 14.2), which was originally the principal use for
Cheetah. So when you use #extends, Cheetah changes that template's
main method to .writeBody() to get it out of the way and prevent it
from overriding the base template's .respond().
Unfortunately this assumption breaks down if the template is used in
other ways. For instance, you may want to use the main method in the
highest-level leaf template, and treat the base template(s) as merely
a library of methods/attributes. In that case, the leaf template needs
#implements respond to change its main method name back to .respond()
(or whatever your application desires to call). Likewise, if your main
method is in one of the intermediate templates in an inheritance
chain, that template needs #implements respond.
The other way the assumption breaks down is if the main method is in
the base template but that template extends a pure Python class.
Cheetah sees the #extends and dutifully but incorrectly renames the
method to .writeBody(), so you have to use #implements respond to
change it back. Otherwise the dummy .respond() in Cheetah.Template is
found, which outputs... nothing. So if you're using #extends and get
no output, the first thing you should think is, ``Do I need to add
#implements respond somewhere?''
8.4 #set
Syntax:
#set [global] $var = EXPR
#set is used to create and update local variables at run time. The
expression may be any Python expression. Remember to preface variable
names with $ unless they're part of an intermediate result in a list
comprehension.
Here are some examples:
#set $size = $length * 1096
#set $buffer = $size + 1096
#set $area = $length * $width
#set $namesList = ['Moe','Larry','Curly']
#set $prettyCountry = $country.replace(' ', ' ')
#set variables are useful to assign a short name to a
$deeply.nested.value, to a calculation, or to a printable version of a
value. The last example above converts any spaces in the 'country'
value into HTML non-breakable-space entities, to ensure the entire
value appears on one line in the browser.
#set variables are also useful in #if expressions, but remember that
complex logical routines should be coded in Python, not in Cheetah!
#if $size > 1500
#set $adj = 'large'
#else
#set $adj = 'small'
#end if
Or Python's one-line equivalent, "A and B or C". Remember that in this
case, B must be a true value (not None, '', 0, [] or ).
#set $adj = $size > 1500 and 'large' or 'small'
(Note: Cheetah's one-line #if will not work for this, since it
produces output rather than setting a variable.
You can also use the augmented assignment operators:
## Increment $a by 5.
#set $a += 5
By default, #set variables are not visible in method calls or include
files unless you use the global attribute: #set global $var =
EXPRESSION. Global variables are visible in all methods, nested
templates and included files. Use this feature with care to prevent
surprises.
8.5 #del
Syntax:
#del $var
#del is the opposite of #set. It deletes a local variable. Its usage
is just like Python's del statement:
#del $myVar
#del $myVar, $myArray[5]
Only local variables can be deleted. There is no directive to delete a
#set global variable, a searchList variable, or any other type of
variable.
8.6 #attr
Syntax:
#attr $var = EXPR
The #attr directive creates class attributes in the generated Python
class. It should be used to assign simple Python literals such as
numbers or strings. In particular, the expression must not depend on
searchList values or #set variables since those are not known at
compile time.
#attr $title = "Rob Roy"
#attr $author = "Sir Walter Scott"
#attr $version = 123.4
This template or any child template can output the value thus:
$title, by $author, version $version
If you have a library of templates derived from etexts
(http://www.gutenberg.org/), you can extract the titles and authors
and put them in a database (assuming the templates have been compiled
into .py template modules):
8.7 #def
Syntax:
#def METHOD[(ARGUMENTS)]
#end def
Or the one-line variation:
#def METHOD[(ARGUMENTS)] : TEXT_AND_PLACEHOLDERS
The #def directive is used to define new methods in the generated
Python class, or to override superclass methods. It is analogous to
Python's def statement. The directive is silent, meaning it does not
itself produce any output. However, the content of the method will be
inserted into the output (and the directives executed) whenever the
method is later called by a $placeholder.
#def myMeth()
This is the text in my method
$a $b $c(123) ## these placeholder names have been defined elsewhere
#end def
## and now use it...
$myMeth()
The arglist and parentheses can be omitted:
#def myMeth
This is the text in my method
$a $b $c(123)
#end def
## and now use it...
$myMeth
Methods can have arguments and have defaults for those arguments, just
like in Python. Remember the $ before variable names:
#def myMeth($a, $b=1234)
This is the text in my method
$a - $b
#end def
## and now use it...
$myMeth(1)
The output from this last example will be:
This is the text in my method
1 - 1234
There is also a single line version of the #def directive. Unlike the
multi-line directives, it uses a colon (:) to delimit the method
signature and body:
#attr $adj = 'trivial'
#def myMeth: This is the $adj method
$myMeth
Leading and trailing whitespace is stripped from the method. This is
in contrast to:
#def myMeth2
This is the $adj method
#end def
where the method includes a newline after "method". If you don't want
the newline, add #slurp:
#def myMeth3
This is the $adj method#slurp
#end def
Because #def is handled at compile time, it can appear above or below
the placeholders that call it. And if a superclass placeholder calls a
method that's overridden in a subclass, it's the subclass method that
will be called.
8.8 #block ... #end block
The #block directive allows you to mark a section of your template
that can be selectively reimplemented in a subclass. It is very useful
for changing part of a template without having to copy-paste-and-edit
the entire thing. The output from a template definition that uses
blocks will be identical to the output from the same template with the
#block ... #end block tags removed.
(Note: don't be confused by the generic word `block'' in this Guide,
which means a section of code inside any #TAG ...#end TAG pair. Thus,
an if-block, for-block, def-block, block-block etc. In this section we
are talking only of block-blocks.)
To reimplement the block, use the #def directive. The magical effect
is that it appears to go back and change the output text at the point
the original block was defined rather than at the location of the
reimplementation.
#block testBlock
Text in the contents
area of the block directive
#if $testIt
$getFoo()
#end if
#end block testBlock
You can repeat the block name in the #end block directive or not, as
you wish.
#block directives can be nested to any depth.
#block outerBlock
Outer block contents
#block innerBlock1
inner block1 contents
#end block innerBlock1
#block innerBlock2
inner block2 contents
#end block innerBlock2
#end block outerBlock
Note that the name of the block is optional for the #end block tag.
Technically, #block directive is equivalent to a #def directive
followed immediately by a #placeholder for the same name. In fact,
that's what Cheetah does. Which means you can use $theBlockName
elsewhere in the template to output the block content again.
There is a one-line #block syntax analagous to the one-line #def.
The block must not require arguments because the implicit placeholder
that's generated will call the block without arguments.
9 Flow Control
9.1 #for ... #end for
Syntax:
#for $var in EXPR
#end for
The #for directive iterates through a sequence. The syntax is the same
as Python, but remember the $ before variables.
Here's a simple client listing:
#for $client in $service.clients
| $client.surname, $client.firstname |
$client.email |
#end for
Here's how to loop through the keys and values of a dictionary:
#for $key, $value in $dict.items()
$key: $value
#end for
Here's how to create list of numbers separated by hyphens. This ``#end
for'' tag shares the last line to avoid introducing a newline
character after each hyphen.
#for $i in range(15)
$i - #end for
If the location of the #end for offends your sense of indentational
propriety, you can do this instead:
#for $i in $range(15)
$i - #slurp
#end for
The previous two examples will put an extra hyphen after last number.
Here's how to get around that problem, using the #set directive, which
will be dealt with in more detail below.
#set $sep = ''
#for $name in $names
$sep$name
#set $sep = ', '
#end for
Although to just put a separator between strings, you don't need a for
loop:
#echo ', '.join($names)
9.2 #repeat ... #end repeat
Syntax:
#repeat EXPR
#end repeat
Do something a certain number of times. The argument may be any
numeric expression. If it's zero or negative, the loop will execute
zero times.
#repeat $times + 3
She loves me, she loves me not.
#repeat
She loves me.
Inside the loop, there's no way to tell which iteration you're on. If
you need a counter variable, use #for instead with Python's range
function. Since Python's ranges are base 0 by default, there are two
ways to start counting at 1. Say we want to count from 1 to 5, and
that $count is 5.
#for $i in $range($count)
#set $step = $i + 1
$step. Counting from 1 to $count.
#end for
#for $i in $range(1, $count + 1)
$i. Counting from 1 to $count.
#end for
A previous implementation used a local variable $i as the repeat
counter. However, this prevented instances of #repeat from being
nested. The current implementation does not have this problem as it
uses a new local variable for every instance of #repeat.
9.3 #while ... #end while
Syntax:
#while EXPR
#end while
#while is the same as Python's while statement. It may be followed by
any boolean expression:
#while $someCondition('arg1', $arg2)
The condition is true.
#end while
Be careful not to create an infinite loop. #while 1 will loop until
the computer runs out of memory.
9.4 #if ... #else if ... #else ... #end if
Syntax:
#if EXPR
#else if EXPR
#elif EXPR
#else
#end if
The #if directive and its kin are used to display a portion of text
conditionally. #if and #else if should be followed by a true/false
expression, while #else should not. Any valid Python expression is
allowed. As in Python, the expression is true unless it evaluates to
0, '', None, an empty list, or an empty dictionary. In deference to
Python, #elif is accepted as a synonym for #else if.
Here are some examples:
#if $size >= 1500
It's big
#else if $size < 1500 and $size > 0
It's small
#else
It's not there
#end if
#if $testItem($item)
The item $item.name is OK.
#end if
Here's an example that combines an #if tag with a #for tag.
#if $people
| Name |
Address |
Phone |
#for $p in $people
| $p.name |
$p.address |
$p.phone |
#end for
#else
Sorry, the search did not find any people.
#end if
See section 7.3 for the one-line #if directive, which is equivalent to
Perl's and C's ?: operator.
9.5 #unless ... #end unless
Syntax:
#unless EXPR
#end unless
#unless is the opposite of #if: the text is executed if the condition
is false. Sometimes this is more convenient. #unless EXPR is
equivalent to #if not (EXPR).
#unless $alive
This parrot is no more! He has ceased to be!
'E's expired and gone to meet 'is maker! ...
THIS IS AN EX-PARROT!!
#end unless
You cannot use #else if or #else inside an #unless construct. If you
need those, use #if instead.
9.6 #break and #continue
Syntax:
#break
#continue
These directives are used as in Python. #break will exit a #for loop
prematurely, while #continue will immediately jump to the next
iteration in the #for loop.
In this example the output list will not contain ``10 - ''.
#for $i in range(15)
#if $i == 10
#continue
#end if
$i - #slurp
#end for
In this example the loop will exit if it finds a name that equals
'Joe':
#for $name in $names
#if $name == 'Joe'
#break
#end if
$name - #slurp
#end for
9.7 #pass
Syntax:
#pass
The #pass directive is identical to Python pass statement: it does
nothing. It can be used when a statement is required syntactically but
the program requires no action.
The following example does nothing if only $A is true
#if $A and $B
do something
#elif $A
#pass
#elif $B
do something
#else
do something
#end if
9.8 #stop
Syntax:
#stop
The #stop directive is used to stop processing of a template at a
certain point. The output will show only what has been processed up to
that point.
When #stop is called inside an #include it skips the rest of the
included code and continues on from after the #include directive. stop
the processing of the included code. Likewise, when #stop is called
inside a #def or #block, it stops only the #def or #block.
A cat
#if 1
sat on a mat
#stop
watching a rat
#end if
in a flat.
will print
A cat
sat on a mat
And
A cat
#block action
sat on a mat
#stop
watching a rat
#end block
in a flat.
will print
A cat
sat on a mat
in a flat.
9.9 #return
Syntax:
#return
This is used as in Python. #return will exit the current method with a
default return value of None or the value specified. It may be used
only inside a #def or a #block.
Note that #return is different from the #stop directive, which returns
the sum of all text output from the method in which it is called. The
following examples illustrate this point:
1
$test[1]
3
#def test
1.5
#if 1
#return '123'
#else
99999
#end if
#end def
will produce
1
2
3
while
1
$test
3
#def test
1.5
#if 1
#stop
#else
99999
#end if
#end def
will produce
1
1.5
3
10 Error Handling
There are two ways to handle runtime errors (exceptions) in Cheetah.
The first is with the Cheetah directives that mirror Python's
structured exception handling statements. The second is with Cheetah's
ErrorCatcher framework. These are described below.
10.1 #try ... #except ... #end try, #finally, and #assert
Cheetah's exception-handling directives are exact mirrors Python's
exception-handling statements. See Python's documentation for details.
The following Cheetah code demonstrates their use:
#try
$mightFail()
#except
It failed
#end try
#try
#assert $x == $y
#except AssertionError
They're not the same!
#end try
#try
#raise ValueError
#except ValueError
#pass
#end try
#try
$mightFail()
#except ValueError
Hey, it raised a ValueError!
#except NameMapper.NotFound
Hey, it raised a NameMapper.NotFound!
#else
It didn't raise anything!
#end try
#try
$mightFail()
#finally
$cleanup()
#end try
Like Python, #except and #finally cannot appear in the same try-block,
but can appear in nested try-blocks.
10.2 #errorCatcher and ErrorCatcher objects
Syntax:
#errorCatcher CLASS
#errorCatcher $PLACEHOLDER_TO_AN_ERROR_CATCHER_INSTANCE
ErrorCatcher is a debugging tool that catches exceptions that occur
inside $placeholder tags and provides a customizable warning to the
developer. Normally, the first missing namespace value raises a
NameMapper.NotFound error and halts the filling of the template. This
requires the developer to resolve the exceptions in order without
seeing the subsequent output. When an ErrorCatcher is enabled, the
developer can see all the exceptions at once as well as the template
output around them.
The Cheetah.ErrorCatchers module defines the base class for
ErrorCatchers:
class ErrorCatcher:
_exceptionsToCatch = (NameMapper.NotFound,)
def __init__(self, templateObj):
pass
def exceptions(self):
return self._exceptionsToCatch
def warn(self, exc_val, code, rawCode, lineCol):
return rawCode
This ErrorCatcher catches NameMapper.NotFound exceptions and leaves
the offending placeholder visible in its raw form in the template
output. If the following template is executed:
#errorCatcher Echo
#set $iExist = 'Here I am!'
Here's a good placeholder: $iExist
Here's bad placeholder: $iDontExist
the output will be:
Here's a good placeholder: Here I am!
Here's bad placeholder: $iDontExist
The base class shown above is also accessible under the alias
Cheetah.ErrorCatchers.Echo. Cheetah.ErrorCatchers also provides a
number of specialized subclasses that warn about exceptions in
different ways. Cheetah.ErrorCatchers.BigEcho will output
Here's a good placeholder: Here I am!
Here's bad placeholder: ===============<$iDontExist could not be found>==
=============
ErrorCatcher has a significant performance impact and is turned off by
default. It can also be turned on with the Template class'
'errorCatcher' keyword argument. The value of this argument should
either be a string specifying which of the classes in
Cheetah.ErrorCatchers to use, or a class that subclasses
Cheetah.ErrorCatchers.ErrorCatcher. The #errorCatcher directive can
also be used to change the errorCatcher part way through a template.
Cheetah.ErrorCatchers.ListErrors will produce the same ouput as Echo
while maintaining a list of the errors that can be retrieved later. To
retrieve the list, use the Template class' 'errorCatcher' method to
retrieve the errorCatcher and then call its listErrors method.
ErrorCatcher doesn't catch exceptions raised inside directives.
11 Instructions to the Parser/Compiler
11.1 #breakpoint
Syntax:
#breakpoint
#breakpoint is a debugging tool that tells the parser to stop parsing
at a specific point. All source code from that point on will be
ignored.
The difference between #breakpoint and #stop is that #stop occurs in
normal templates (e.g., inside an #if) but #breakpoint is used only
when debugging Cheetah. Another difference is that #breakpoint
operates at compile time, while #stop is executed at run time while
filling the template.
11.2 #compiler-settings
Syntax:
#compiler-settings
key = value (no quotes)
#end compiler-settings
#compiler-settings reset
The #compiler-settings directive overrides Cheetah's standard
settings, changing how it parses source code and generates Python
code. This makes it possible to change the behaviour of Cheetah's
parser/compiler for a certain template, or within a portion of the
template.
The reset argument reverts to the default settings. With reset,
there's no end tag.
Here are some examples of what you can do:
$myVar
#compiler-settings
cheetahVarStartToken = @
#end compiler-settings
@myVar
#compiler-settings reset
$myVar
## normal comment
#compiler-settings
commentStartToken = //
#end compiler-settings
// new style of comment
#compiler-settings reset
## back to normal comments
#slurp
#compiler-settings
directiveStartToken = %
#end compiler-settings
%slurp
%compiler-settings reset
#slurp
Here's a partial list of the settings you can change:
1. syntax settings
1. cheetahVarStartToken
2. commentStartToken
3. multilineCommentStartToken
4. multilineCommentEndToken
5. directiveStartToken
6. directiveEndToken
2. code generation settings
1. commentOffset
2. outputRowColComments
3. defDocStrMsg
4. useNameMapper
5. useAutocalling
6. reprShortStrConstants
7. reprNewlineThreshold
The meaning of these settings and their default values will be
documented in the future.
12 Fine Control over Cheetah-generated Python modules
12.1 Setting the source code encoding: #encoding
Including
#encoding UTF-8
in your Cheetah .tmpl file will result in
# -*- coding: UTF-8 -*-
being appended to the top of the .py module file that Cheetah's
compiler generates.
See http://www.python.org/doc/2.3/whatsnew/section-encodings.html for
more details.
12.2 Setting the sh-bang: #shBang
Including
#shBang #!/usr/local/bin/python2.3
in your Cheetah .tmpl file will result in
#!/usr/local/bin/python2.3
being appended to the top of the .py module file that Cheetah's
compiler generates.
The default sh-bang is
#!/usr/bin/env python
13 Tips, Tricks and Troubleshooting
This chapter contains short stuff that doesn't fit anywhere else.
See the Cheetah FAQ for more specialized issues and for
troubleshooting tips. Check the wiki periodically for recent tips
contributed by users. If you get stuck and none of these resources
help, ask on the mailing list.
13.1 Placeholder Tips
Here's how to do certain important lookups that may not be obvious.
For each, we show first the Cheetah expression and then the Python
equivalent, because you can use these either in templates or in pure
Python subclasses. The Cheetah examples use NameMapper shortcuts
(uniform dotted notation, autocalling) as much as possible.
To verify whether a variable exists in the searchList:
$varExists('theVariable')
self.varExists('theVariable')
This is useful in #if or #unless constructs to avoid a
#NameMapper.NotFound error if the variable doesn't exist. For
instance, a CGI GET parameter that is normally supplied but in this
case the user typed the URL by hand and forgot the parameter (or
didn't know about it). (.hasVar is a synonym for .varExists.)
To look up a variable in the searchList from a Python method:
self.getVar('theVariable')
self.getVar('theVariable', myDefault)
This is the equivalent to $theVariable in the template. If the
variable is missing, it returns the second argument, myDefault, if
present, or raises NameMapper.NotFound if there is no second argument.
However, it usually easier to write your method so that all needed
searchList values come in as method arguments. That way the caller can
just use a $placeholder to specify the argument, which is less verbose
than you writing a getVar call.
To do a ``safe'' placeholder lookup that returns a default value if
the variable is missing:
$getVar('theVariable', None)
$getVar('theVariable', $myDefault)
To get an environmental variable, put os.environ on the searchList as
a container. Or read the envvar in Python code and set a placeholder
variable for it.
Remember that variables found earlier in the searchList override
same-name variables located in a later searchList object. Be careful
when adding objects containing other variables besides the ones you
want (e.g., os.environ, CGI parameters). The "other" variables may
override variables your application depends on, leading to
hard-to-find bugs. Also, users can inadvertently or maliciously set an
environmental variable or CGI parameter you didn't expect, screwing up
your program. To avoid all this, know what your namespaces contain,
and place the namespaces you have the most control over first. For
namespaces that could contain user-supplied "other" variables, don't
put the namespace itself in the searchList; instead, copy the needed
variables into your own "safe" namespace.
13.2 Diagnostic Output
If you need send yourself some debugging output, you can use #silent
to output it to standard error:
#silent $sys.stderr.write("Incorrigible var is '$incorrigible'.\n")
#silent $sys.stderr.write("Is 'unknown' in the searchList? " +
$getVar("unknown", "No.") + "\n" )
(Tip contributed by Greg Czajkowski.)
13.3 When to use Python methods
You always have a choice whether to code your methods as Cheetah #def
methods or Python methods (the Python methods being located in a class
your template inherits). So how do you choose?
Generally, if the method consists mostly of text and placeholders, use
a Cheetah method (a #def method). That's why #def exists, to take the
tedium out of writing those kinds of methods. And if you have a couple
#if stanzas to #set some variables, followed by a #for loop, no big
deal. But if your method consists mostly of directives and only a
little text, you're better off writing it in Python. Especially be on
the watch for extensive use of #set, #echo and #silent in a Cheetah
method-it's a sure sign you're probably using the wrong language. Of
course, though, you are free to do so if you wish.
Another thing that's harder to do in Cheetah is adjacent or nested
multiline stanzas (all those directives with an accompanying #end
directive). Python uses indentation to show the beginning and end of
nested stanzas, but Cheetah can't do that because any indentation
shows up in the output, which may not be desired. So unless all those
extra spaces and tabs in the output are acceptable, you have to keep
directives flush with the left margin or the preceding text.
The most difficult decisions come when you have conflicting goals.
What if a method generates its output in parts (i.e., output
concatenation), contains many searchList placeholders and lots of
text, and requires lots of #if ...#set ...#else #set ...#end if
stanzas. A Cheetah method would be more advantageous in some ways, but
a Python method in others. You'll just have to choose, perhaps coding
groups of methods all the same way. Or maybe you can split your method
into two, one Cheetah and one Python, and have one method call the
other. Usually this means the Cheetah method calling the Python method
to calculate the needed values, then the Cheetah method produces the
output. One snag you might run into though is that #set currently can
set only one variable per statement, so if your Python method needs to
return multiple values to your Cheetah method, you'll have to do it
another way.
13.4 Calling superclass methods, and why you have to
If your template or pure Python class overrides a standard method or
attribute of Template or one of its base classes, you should call the
superclass method in your method to prevent various things from
breaking. The most common methods to override are .awake and
.__init__. .awake is called automatically by Webware early during the
web transaction, so it makes a convenient place to put Python
initialization code your template needs. You'll definitely want to
call the superclass .awake because it sets up many wonderful
attributes and methods, such as those to access the CGI input fields.
There's nothing Cheetah-specific to calling superclass methods, but
because it's vital, we'll recap the standard Python techniques here.
We mention only the solution for old-style classes because Cheetah
classes are old-style (in other Python documentation, you will find
the technique for new-style classes, but they are not listed here
because they cannot be used with Cheetah if you use
dynamically-compiled templates).
from Cheetah.Template import Template
class MyClass(Template):
def awake(self, trans):
Template.awake(self, trans)
... great and exciting features written by me ...
[ @@MO: Need to test this. .awake is in Servlet, which is a superclass
of Template. Do we really need both imports? Can we call
Template.awake? ]
To avoid hardcoding the superclass name, you can use this function
callbase(), which emulates super() for older versions of Python. It
also works even super() does exist, so you don't have to change your
servlets immediately when upgrading. Note that the argument sequence
is different than super uses.
===========================================================================
# Place this in a module SOMEWHERE.py . Contributed by Edmund Lian.
class CallbaseError(AttributeError):
pass
def callbase(obj, base, methodname='__init__', args=(), kw={},
raiseIfMissing=None):
try: method = getattr(base, methodname)
except AttributeError:
if raiseIfMissing:
raise CallbaseError, methodname
return None
if args is None: args = ()
return method(obj, *args, **kw)
===========================================================================
# Place this in your class that's overriding .awake (or any method).
from SOMEWHERE import callbase
class MyMixin:
def awake(self, trans):
args = (trans,)
callbase(self, MyMixin, 'awake', args)
... everything else you want to do ...
===========================================================================
13.5 All methods
Here is a list of all the standard methods and attributes that can be
accessed from a placeholder. Some of them exist for you to call,
others are mainly used by Cheetah internally but you can call them if
you wish, and others are only for internal use by Cheetah or Webware.
Do not use these method names in mixin classes (#extends, section 8.2)
unless you intend to override the standard method.
Variables with a star prefix (*) are frequently used in templates or
in pure Python classes.
Inherited from Cheetah.Template
compile(source=None, file=None, moduleName=None,
mainMethodName='respond') Compile the template. Automatically
called by .__init__.
generatedModuleCode() Return the module code the compiler
generated, or None if no compilation took place.
generatedClassCode() Return the class code the compiler
generated, or None if no compilation took place.
* searchList() Return a reference to the underlying search
list. (a list of objects). Use this to print out your
searchList for debugging. Modifying the returned list will
affect your placeholder searches!
* errorCatcher() Return a reference to the current error
catcher.
* refreshCache(cacheKey=None) If 'cacheKey' is not None,
refresh that item in the cache. If None, delete all items in
the cache so they will be recalculated the next time they are
encountered.
* shutdown() Break reference cycles before discarding a
servlet.
* getVar(varName, default=NoDefault, autoCall=True) Look up a
variable in the searchList. Same as $varName but allows you to
specify a default value and control whether autocalling occurs.
* varExists(varName, autoCall=True)
* getFileContents(path) Read the named file. If used as a
placeholder, inserts the file's contents in the output without
interpretation, like #include raw. If used in an expression,
returns the file's content (e.g., to assign it to a variable).
runAsMainProgram() This is what happens if you run a .py
template module as a standalone program.
Inherited from Cheetah.Utils.WebInputMixin
nonNumericInputError Exception raised by .webInput.
* webInput(...) Convenience method to access GET/POST variables
from a Webware servlet or CGI script, or Webware cookie or
session variables. See section 14.7 for usage information.
Inherited from Cheetah.SettingsManager
setting(name, default=NoDefault) Get a compiler setting.
hasSetting(name) Does this compiler setting exist?
setSetting(name, value) Set setting 'name' to 'value'. See
#compiler-settings, section 11.2.
settings() Return the underlying settings dictionary. (Warning:
modifying this dictionary will change Cheetah's behavior.)
copySettings() Return a copy of the underlying settings
dictionary.
deepcopySettings() Return a deep copy of the underlying
settings dictionary. See Python's copy module.
updateSettings(newSettings, merge=True) Update Cheetah's
compiler settings from the 'newSettings' dictionary. If 'merge'
is true, update only the names in newSettings and leave the
other names alone. (The SettingsManager is smart enough to
update nested dictionaries one key at a time rather than
overwriting the entire old dictionary.) If 'merge' is false,
delete all existing settings so that the new ones are the only
settings.
updateSettingsFromPySrcStr(theString, merge=True) Same, but
pass a string of name=value pairs rather than a dictionary, the
same as you would provide in a #compiler-settings directive,
section 11.2.
updateSettingsFromPySrcFile(path, merge=True) Same, but exec a
Python source file and use the variables it contains as the new
settings. (e.g., cheetahVarStartToken = "@").
updateSettingsFromConfigFile(path, **kw) Same, but get the new
settings from a text file in ConfigParser format (similar to
Windows' *.ini file format). See Python's ConfigParser module.
updateSettingsFromConfigFileObj Same, but read the open file
object 'inFile' for the new settings.
updateSettingsFromConfigStr(configStr, convert=True, merge=True
Same, but read the new settings from a string in ConfigParser
format.
writeConfigFile(path) Write the current compiler settings to a
file named 'path' in *.ini format.
getConfigString() Return a string containing the current
compiler settings in *.ini format.
Inherited from Cheetah.Servlet
Do not override these in a subclass or