Edited by Mike Orr and Tavis Rudd
cheetahtemplate-discuss@lists.sourceforge.net
©Copyright 2001-2005, The Cheetah Development Team. This document may be copied and modified under the terms of the Open Publication License http://www.opencontent.org/openpub/
This Users' Guide provides a technical overview and reference for the Cheetah template system. Knowledge of Python and object-oriented programming is assumed. The emphasis in this Guide is on features useful in a wide variety of situations. Information on less common situations and troubleshooting tips are gradually being moved to the Cheetah FAQ. There is also a Cheetah Developer's Guide for those who want to know what goes on under the hood.
This Guide also contains examples of integrating Cheetah with Webware for Python. You will have to learn Webware from its own documentation in order to build a Webware + Cheetah site.
Cheetah is a Python-powered template engine and code generator. It may be used as a standalone utility or combined with other tools. Cheetah has many potential uses, but web developers looking for a viable alternative to ASP, JSP, PHP and PSP are expected to be its principle user group.
Cheetah:
Cheetah integrates tightly with Webware for Python (http://webware.sourceforge.net/): a Python-powered application server and persistent servlet framework. Webware provides automatic session, cookie, and user management and can be used with almost any operating-system, web server, or database. Through Python, it works with XML, SOAP, XML-RPC, CORBA, COM, DCOM, LDAP, IMAP, POP3, FTP, SSL, etc.. Python supports structured exception handling, threading, object serialization, unicode, string internationalization, advanced cryptography and more. It can also be extended with code and libraries written in C, C++, Java and other languages.
Like Python, Cheetah and Webware are Open Source software and are supported by active user communities. Together, they are a powerful and elegant framework for building dynamic web sites.
Like its namesake, Cheetah is fast, flexible and powerful.
Cheetah's design was guided by these principles:
A clean separation makes it easier for a team of content writers, HTML/graphic designers, and programmers to work together without stepping on each other's toes and polluting each other's work. The HTML framework and the content it contains are two separate things, and analytical calculations (program code) is a third thing. Each team member should be able to concentrate on their specialty and to implement their changes without having to go through one of the others (i.e., the dreaded ``webmaster bottleneck'').
While it should be easy to develop content, graphics and program code separately, it should be easy to integrate them together into a website. In particular, it should be easy:
Cheetah does not use HTML/XML-style tags like some other template languages for
the following reasons:
Cheetah is not limited to HTML,
HTML-style tags are hard to distinguish from real HTML tags,
HTML-style tags are not visible in rendered HTML when something goes wrong,
HTML-style tags often lead to invalid HTML (e.g.,
<img src="<template-directive>">
),
Cheetah tags are less verbose and easier to understand than HTML-style tags,
and HTML-style tags aren't compatible with most WYSIWYG editors
Besides being much more compact, Cheetah also has some advantages over languages that put information inside the HTML tags, such as Zope Page Templates or PHP: HTML or XML-bound languages do not work well with other languages, While ZPT-like syntaxes work well in many ways with WYSIWYG HTML editors, they also give up a significant advantage of those editors - concrete editing of the document. When logic is hidden away in (largely inaccessible) tags it is hard to understand a page simply by viewing it, and it is hard to confirm or modify that logic.
Here's a very simple example that illustrates some of Cheetah's basic syntax:
<HTML> <HEAD><TITLE>$title</TITLE></HEAD> <BODY> <TABLE> #for $client in $clients <TR> <TD>$client.surname, $client.firstname</TD> <TD><A HREF="mailto:$client.email">$client.email</A></TD> </TR> #end for </TABLE> </BODY> </HTML>
Compare this with PSP:
<HTML> <HEAD><TITLE><%=title%></TITLE></HEAD> <BODY> <TABLE> <% for client in clients: %> <TR> <TD><%=client['surname']%>, <%=client['firstname']%></TD> <TD><A HREF="mailto:<%=client['email']%>"><%=client['email']%></A></TD> </TR> <%end%> </TABLE> </BODY> </HTML>
Section 3.7 has a more typical example that shows how to get the plug-in values into Cheetah, and section 4.2 explains how to turn your template definition into an object-oriented Python module.
This example uses an HTML form to ask the user's name, then invokes itself again to display a personalized friendly greeting.
<HTML><HEAD><TITLE>My Template-Servlet</TITLE></HEAD><BODY> #set $name = $request.field('name', None) #if $name Hello $name #else <FORM ACTION="" METHOD="GET"> Name: <INPUT TYPE="text" NAME="name"><BR> <INPUT TYPE="submit"> </FORM> #end if </BODY></HTML>
To try it out for yourself on a Webware system:
cheetah compile test.tmpl
''. This produces
test.py (a .py template module) in the same directory.
At the first request, field `name' will be blank (false) so the ``#else'' portion will execute and present a form. You type your name and press submit. The form invokes the same page. Now `name' is true so the ``#if'' portion executes, which displays the greeting. The ``#set'' directive creates a local variable that lasts while the template is being filled.
Cheetah is stable, production quality, post-beta code. Cheetah's syntax, semantics and performance have been generally stable since a performance overhaul in mid 2001. Most of the changes since October 2001 have been in response to specific requests by production sites, things they need that we hadn't considered.
As of summer 2003, we are putting in the final touches before the 1.0 release.
The TODO and BUGS files in the Cheetah distribution show what we're working on now or planning to work on. There's also a ToDo page on the wiki (see below), which is updated less often. The WishList page on the wiki shows requested features we're considering but haven't commited to.
Cheetah releases and other stuff can be obtained from the the Cheetah Web site: http://CheetahTemplate.sourceforge.net
Cheetah discussions take place on the mailing list cheetahtemplate-discuss@lists.sourceforge.net. This is where to hear the latest news first.
The Cheetah wiki is becoming an increasingly popular place to list examples of Cheetah in use, provide cookbook tips for solving various problems, and brainstorm ideas for future versions of Cheetah. http://www.cheetahtemplate.org/wiki(The wiki is actually hosted at http://cheetah.colorstudy.net/twiki/bin/view/Cheetah/WebHome, but the other URL is easier to remember.) For those unfamiliar with a wiki, it's a type of Web site that readers can edit themselves to make additions or corrections to. Try it. Examples and tips from the wiki will also be considered for inclusion in future versions of this Users' Guide.
If you encounter difficulties, or are unsure about how to do something, please post a detailed message to the list.
Cheetah is the work of many volunteers. If you use Cheetah please share your experiences, tricks, customizations, and frustrations.
If you think there is a bug in Cheetah, send a message to the e-mail list with the following information:
Cheetah is one of several templating frameworks that grew out of a `templates' thread on the Webware For Python email list. Tavis Rudd, Mike Orr, Chuck Esterbrook and Ian Bicking are the core developers.
We'd like to thank the following people for contributing valuable advice, code and encouragement: Geoff Talvola, Jeff Johnson, Graham Dumpleton, Clark C. Evans, Craig Kattner, Franz Geiger, Geir Magnusson, Tom Schwaller, Rober Kuzelj, Jay Love, Terrel Shumway, Sasa Zivkov, Arkaitz Bitorika, Jeremiah Bellomy, Baruch Even, Paul Boddie, Stephan Diehl, Chui Tey, Michael Halle, Edmund Lian and Aaron Held.
The Velocity, WebMacro and Smarty projects provided inspiration and design ideas. Cheetah has benefitted from the creativity and energy of their developers. Thank you.
Cheetah.Utils.optik is based on a third-party package Optik by Gregory P Ward. Optik's license is in appendix D.
Permission to use, copy, modify, and distribute this software for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of the authors not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.
THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
These terms do not apply to the Cheetah.Utils.optik package. Optik's license is in appendix D.
Template is an informal term meaning a template definition, a template instance or a template class. A template definition is what the human template maintainer writes: a string consisting of text, placeholders and directives. Placeholders are variables that will be looked up when the template is filled. Directives are commands to be executed when the template is filled, or instructions to the Cheetah compiler. The conventional suffix for a file containing a template definition is .tmpl.
There are two things you can do with a template: compile it or fill it. Filling is the reason you have a template in the first place: to get a finished string out of it. Compiling is a necessary prerequisite: the Cheetah compiler takes a template definition and produces Python code to create the finished string. Cheetah provides several ways to compile and fill templates, either as one step or two.
Cheetah's compiler produces a subclass of Cheetah.Template
specific to that template definition; this is called the generated
class. A template instance is an instance of a generated class.
If the user calls the Template
constructor directly (rather than a
subclass constructor), s/he will get what appears to be an instance of
Template
but is actually a subclass created on-the-fly.
The user can make the subclass explicit by using the ``cheetah compile'' command to write the template class to a Python module. Such a module is called a .py template module.
The Template Definition Language - or the ``Cheetah language'' for short - is the syntax rules governing placeholders and directives. These are discussed in sections 5 and following in this Guide.
To fill a template, you call its main method. This is normally
.respond()
, but it may be something else, and you can use the
#implements
directive to choose the method name. (Section
8.3.
A template-servlet is a .py template module in a Webware servlet directory. Such templates can be filled directly through the web by requesting the URL. ``Template-servlet'' can also refer to the instance being filled by a particular web request. If a Webware servlet that is not a template-servlet invokes a template, that template is not a template-servlet either.
A placeholder tag is the substring in the template definition that is the placeholder, including the start and end delimeters (if there is an end delimeter). The placeholder name is the same but without the delimeters.
Placeholders consist of one or more identifiers separated by periods
(e.g., a.b
). Each identifier must follow the same rules as Python
identifiers; that is, a letter or underscore followed by one or more letters,
digits or underscores. (This is the regular expression
[A-Za-z_][A-Za-z0-9_]*
.)
The first (or only) identifier of a placeholder name represents a variable to be looked up. Cheetah looks up variables in various namespaces: the searchList, local variables, and certain other places. The searchList is a list of objects (containers) with attributes and/or keys: each container is a namespace. Every template instance has exactly one searchList. Identifiers after the first are looked up only in the parent object. The final value after all lookups have been performed is the placeholder value.
Placeholders may occur in three positions: top-level, expression and LVALUE. Top-level placeholders are those in ordinary text (``top-level text''). Expression placeholders are those in Python expressions. LVALUE placeholders are those naming a variable to receive a value. (LVALUE is computerese for ``the left side of the equal sign''.) Section 5.3 explains the differences between these three positions.
The routine that does the placeholder lookups is called the NameMapper.
Cheetah's NameMapper supports universal dotted notation and autocalling.
Universal dotted notation means that keys may be written as if they were
attributes: a.b
instead of a['b']
. Autocalling means that
if any identifier's value is found to be a function or method, Cheetah will
call it without arguments if there is no ()
following. More about the
NameMapper is in section 5.5.
Some directives are multi-line, meaning they have a matching #end tag. The lines of text between the start and end tags is the body of the directive. Arguments on the same line as the start tag, in contrast, are considered part of the directive tag. More details are in section 5.8 (Directive Syntax Rules).
Cheetah requires Python release 2.0 or greater, and has been tested with Python 2.0, 2.1 and 2.2. It is known to run on Linux, Windows NT/98/XP, FreeBSD and Solaris, and should run anywhere Python runs.
99% of Cheetah is written in Python. There is one small C module
(_namemapper.so
) for speed, but Cheetah automatically falls back to a
Python equivalent (NameMapper.py
) if the C module is not available.
To install Cheetah in your system-wide Python library:
python setup.py install
at the command prompt.
Cheetah's installation is managed by Python's Distribution Utilities
('distutils'). There are many options for customization. Type ``python
setup.py help''
for more information.
To install Cheetah in an alternate location - someplace outside Python's
site-packages/
directory, use one of these options:
python setup.py install --home /home/tavis python setup.py install --install-lib /home/tavis/lib/python
If you do the systemwide install, all Cheetah modules are installed in the site-packages/Cheetah/ subdirectory of your standard library directory; e.g., /opt/Python2.2/lib/python2.2/site-packages/Cheetah.
Two commands are installed in Python's bin/
directory or a system
bin directory: cheetah
(section 3.5) and
cheetah-compile
(section 4.2).
To uninstall Cheetah, merely delete the site-packages/Cheetah/ directory. Then delete the ``cheetah'' and ``cheetah-compile'' commands from whichever bin/ directory they were put in.
Cheetah comes with a utility cheetah
that provides a command-line
interface to various housekeeping tasks. The command's first argument is
the name of the task. The following commands are currently supported:
cheetah compile [options] [FILES ...] : Compile template definitions cheetah fill [options] [FILES ...] : Fill template definitions cheetah help : Print this help message cheetah options : Print options help message cheetah test : Run Cheetah's regression tests cheetah version : Print Cheetah version number
You only have to type the first letter of the command:
cheetah c
is the same as cheetah compile
.
The test suite is described in the next section. The compile
command will be described in section 4.2,
and the fill
command in section 4.3.
The depreciated cheetah-compile
program does the same thing as
cheetah compile
.
After installing Cheetah, you can run its self-test routine to verify it's working properly on your system. Change directory to any directory you have write permission in (the tests write temporary files). Do not run the tests in the directory you installed Cheetah from, or you'll get unnecessary errors. Type the following at the command prompt:
cheetah test
The tests will run for about three minutes and print a success/failure message. If the tests pass, start Python in interactive mode and try the example in the next section.
Certain test failures are insignificant:
import
it. Reread
the first paragraph in this section about the current directory.
If any other tests fail, please send a message to the e-mail list with a copy of the test output and the following details about your installation:
This tutorial briefly introduces how to use Cheetah from the Python prompt. The following chapters will discuss other ways to use templates and more of Cheetah's features.
The core of Cheetah is the Template
class in the Cheetah.Template
module. The following example shows how to use the Template
class in an
interactive Python session. t
is the Template instance. Lines prefixed
with »>
and ...
are user input. The remaining lines are Python
output.
>>> from Cheetah.Template import Template >>> templateDef = """ ... <HTML> ... <HEAD><TITLE>$title</TITLE></HEAD> ... <BODY> ... $contents ... ## this is a single-line Cheetah comment and won't appear in the output ... #* This is a multi-line comment and won't appear in the output ... blah, blah, blah ... *# ... </BODY> ... </HTML>""" >>> nameSpace = {'title': 'Hello World Example', 'contents': 'Hello World!'} >>> t = Template(templateDef, searchList=[nameSpace]) >>> print t <HTML> <HEAD><TITLE>Hello World Example</TITLE></HEAD> <BODY> Hello World! </BODY> </HTML> >>> print t # print it as many times as you want [ ... same output as above ... ] >>> nameSpace['title'] = 'Example #2' >>> nameSpace['contents'] = 'Hiya Planet Earth!' >>> print t # Now with different plug-in values. <HTML> <HEAD><TITLE>Example #2</TITLE></HEAD> <BODY> Hiya Planet Earth! </BODY> </HTML>
Since Cheetah is extremely flexible, you can achieve the same result this way:
>>> t2 = Template(templateDef) >>> t2.title = 'Hello World Example!' >>> t2.contents = 'Hello World' >>> print t2 [ ... same output as the first example above ... ] >>> t2.title = 'Example #2' >>> t2.contents = 'Hello World!' >>> print t2 [ ... same as Example #2 above ... ]
Or this way:
>>> class Template3(Template): >>> title = 'Hello World Example!' >>> contents = 'Hello World!' >>> t3 = Template3(templateDef) >>> print t3 [ ... you get the picture ... ]
The template definition can also come from a file instead of a string, as we will see in section 4.1.
The above is all fine for short templates, but for long templates or for an application that depends on many templates in a hierarchy, it's easier to store the templates in separate *.tmpl files and use the cheetah compile program to convert them into Python classes in their own modules. This will be covered in section 4.2.
As an appetizer, we'll just briefly mention that you can store constant values inside the template definition, and they will be converted to attributes in the generated class. You can also create methods the same way. You can even use inheritance to arrange your templates in a hierarchy, with more specific templates overriding certain parts of more general templates (e.g., a "page" template overriding a sidebar in a "section" template).
For the minimalists out there, here's a template definition, instantiation and filling all in one Python statement:
>>> print Template("Templates are pretty useless without placeholders.") Templates are pretty useless without placeholders.
You use a precompiled template the same way, except you don't provide a template definition since it was already established:
from MyPrecompiledTemplate import MyPrecompiledTemplate t = MyPrecompiledTemplate() t.name = "Fred Flintstone" t.city = "Bedrock City" print t
As mentioned before, you can do two things with templates: compile them and fill them. (Actually you can query them too, to see their attributes and method values.) Using templates in a Python program was shown in section 3.7 (Quickstart tutorial). Here we'll focus on compiling and filling templates from the shell command line, and how to make .py template modules. The compiling information here is also important for template-servlets, which will be otherwise covered in chapter 14 (Webware).
The heart of Cheetah is the Template
class in the
Cheetah.Template
module. You can use it directly if you have a
template definition in hand, or indirectly through a precompiled template,
which is a subclass. The constructor accepts the following keyword
arguments. (If you're a beginner, learn the first three arguments now;
the others are much less frequent.)
source=
prefix if it's the first argument, as in all the examples below.
The source can be a string literal in your module, or perhaps a string
you read from a database or other data structure.
$placeholder
lookup.
$placeholder
value. You may
specify a class object or string. If a class object,
it must be a subclass of Cheetah.Filters.Filter
. If a string, it
must be the name of one of the filters in filtersLib module (see next
item).
(You may also use the #filter
directive (section
7.9) to switch filters at runtime.)
Cheetah.Filters
. All classes in this module that are
subclasses of Cheetah.Filters.Filter
are considered filters.
$placeholder
errors. You may
specify a class object or string. If a class object,
it must be a subclass of Cheetah.ErrorCatchers.ErrorCatcher
.
If a string, it must be the name of one of the error catchers in
Cheetah.ErrorCatchers
. This is similar to the
#errorCatcher
directive
(section 10.2).
To use Template
directly, you must specify either source
or file
, but not both. To use a precompiled template, you
must not specify either one, because the template definition is already
built into the class. The other arguments, however, may be used in either case.
Here are typical ways to create a template instance:
t = Template("The king is a $placeholder1.")
t = Template(file="fink.tmpl")
t = Template(file=f)
t = Template("The king is a $placeholder1.", searchList=[dict, obj])
t = Template(file="fink.txt", searchList=[dict, obj])
t = Template(file=f, searchList=[dict, obj])
If you use Template
directly, the template definition will be compiled
the first time it's filled. Compilation creates a template-specific class
called the generated class, which is a subclass of Template
. It
then dynamically switches the instance so it's now an instance of this class.
Don't worry if you don't understand this; it works.
When you precompile a template using the ``cheetah compile'' command, it
writes the generated class to a file. Actually, what it writes is the source
code for a Python module that contains the generated class. Again, the
generated class is a subclass of Template
. We call the generated
module a .py template module. Thus, if you always use
precompiled templates (as many people do), you can view Cheetah as a
convenient front-end for writing certain kinds of Python modules, the way
you might use a graphical dialog builder to make a dialog module.
Precompiled templates provide a slight performance boost because the compilation happens only once rather than every time it's instantiated. Also, once you import the .py template module and allow Python to create a .pyc or .pyo file, you skip the Python compiler too. The speed advantage of all this is negligable, but it may make a difference in programs that use templates many times a second.
Template
subclasses Webware's Servlet
class when available,
so the generated class can be used as a Webware servlet. This is practical
only with precompiled templates.
To fill a template, you call its main method. This is normally
.respond()
, but under certain circumstances it's .writeBody()
or
a user-defined name. (Section 8.3 explains why
the method name is not always the same.) However, .__str__()
is
always an alias for the main method, so you can always use
print myTemplateInstance
or str(myTempateInstance)
to fill it.
You can also call any #def
or #block
method and it will fill
just that portion of the template, although this feature is not often used.
To create a .py template module, do either of these:
cheetah compile [options] [FILES ...] cheetah c [options] [FILES ...]
The following options are supported:
--idir DIR, --odir DIR : input/output directories (default: current dir) --iext EXT, --oext EXT : input/output filename extensions (default input: tmpl, default output: py) -R : recurse subdirectories looking for input files --debug : print lots of diagnostic output to standard error --flat : no destination subdirectories --nobackup : don't make backups --stdout, -p : output to standard output (pipe)
Note: If Cheetah can't find your input files, or if it puts output files
in the wrong place, use the --debug
option to see what Cheetah thinks
of your command line.
The most basic usage is:
cheetah compile a.tmpl : writes a.py cheetah compile a.tmpl b.tmpl : writes a.py and b.py
Cheetah will automatically add the default input extension (.tmpl) if the file is not found. So the following two examples are the same as above (provided files ``a'' and ``b'' don't exist):
cheetah compile a : writes a.py (from a.tmpl) cheetah compile a b : writes a.py and b.py
You can override the default input extension and output extension
(py
) using --iext
and --oext
, although there's
little reason to do so. Cheetah assumes the extension has a leading dot
(.) even if you don't specify it.
Use the -R
option to recurse subdirectories:
cheetah compile dir1 : error, file is a directory cheetah compile -R dir1 : look in `dir1' for files to compile cheetah compile : error, no file specified cheetah compile -R : look in current directory for files to compile cheetah compile -R a b dir1 : compile files and recurse
The options --idir
and --odir
allow you to specify that
the source (and/or destination) paths are relative to a certain directory
rather than to the current directory. This is useful if you keep your
*.tmpl and *.py files in separate directory hierarchies. After editing a
source file, just run one of these (or put the command in a script or
Makefile):
cheetah compile --odir /var/webware a.tmpl cheetah compile -R --odir /var/webware cheetah c --odir /var/webware sub/a.tmpl : writes /var/webware/sub/a.py
``cheetah compile'' overwrites any existing .py
file it finds, after
backing it up to FILENAME.py_bak (unless you specify --nobackup
). For
this reason, you should make changes to the .tmpl
version of the
template rather than to the .py
version.
For the same reason, if your template requires custom Python methods or
other Python code, don't put it in the FILENAME.py
file. Instead, put
it in a separate base class and use the #extends
directive to
inherit from it.
Because FILENAME will be used as a class and module name, it must be a valid
Python identifier. For instance, cheetah compile spam-eggs.tmpl
is
illegal because of the hyphen ("-"). This is sometimes inconvenient when
converting a site of HTML files into Webware servlets. Fortunately, the
directory it's in does not have to be an identifier. (Hint: for
date-specific files, try converting 2002/04/12.html to 2002/04/12/index.tmpl.
This also gives you a directory to store images or supplemental files.)
Occasionally you may want output files put directly into the output directory
(or current directory), rather than into a subdirectory parallel to the input
file. The --flat
option does this. Note that this introduces the
possibility that several input files might map to one output file. Cheetah
checks for output file collisions before writing any files, and aborts if there
are any collisions.
cheetah c sub/a.py : writes sub/a.py cheetah c --flat sub/a.py : writes a.py cheetah c --odir DEST sub/a.tmpl : writes DEST/sub/a.py cheetah c --flat --odir DEST sub/a.tmpl : writes DEST/a.py cheetah c --idir /home/henry sub/rollins.tmpl : writes sub/rollins.py cheetah c --flat --idir /home/henry sub/rollins.tmpl : writes rollins.py cheetah c --idir /home/henry --odir /home/henry sub/rollins.tmpl : writes /home/henry/sub/rollins.py cheetah c --flat --idir /home/henry --odir /home/henry sub/rollins.tmpl : writes /home/henry/rollins.py
Whenever ``cheetah compile'' has to create an output directory or subdirectory, it also creates an __init__.py file in it. This file is necessary in order to make Python treat the directory as a Python package.
One of the advantages of .py template modules is that you don't lose any
flexibility. The generated class contains all #attr
values and
#def
/#block
values as ordinary attributes and methods, so you
can read the values individually from other Python tools for any kind of custom
processing you want. For instance, you can extract the titles of all
your templates into a database, or find all the servlets with a certain
$author
value.
You can compile and fill a large number of template definitions from the
command line in one step using cheetah fill
. This compiles the template
in memory; it does not save the .py template module to disk. Instead it
writes a finished output file, which has the extension .html
by default.
All the options to cheetah compile
work the same way here, and there are
also a couple additional options:
--env : put the environment in the searchList --pickle FILE : unpickle FILE and put that object in the searchList
Because you can't provide a searchList on the command line, the
templates must either contain or inherit all the variables it needs,
or use the --env
and --pickle
options to
provide additional variables.
Examples:
cheetah fill a.tmpl : writes a.html cheetah fill a.tmpl b.tmpl : writes a.html and b.html cheetah f --oext txt a : writes a.txt (from a.tmpl)
Using --env
may have security or reliability implications because the
environment normally contains lots of variables you inherited rather than
defining yourself. If any of these variables override any of yours (say a
#def
), you will get incorrect output, may reveal private information,
and may get an exception due to the variable being an unexpected type
(environmental variables are always strings). Your calling program may wish
to clear out the environment before setting environmental variables for the
template.
There are two other differences between ``cheetah compile'' and ``cheetah fill''. Cheetah doesn't create __init__.py files when creating directories in fill mode. Also, the source filenames don't have to be identifiers.
We won't look inside .py template modules in this Guide except to note that they are very different from template definitions. The following template definition fragment:
The number is $Test.unittest.main.
compiles to this:
write("The number is ") write(filter(VFN(VFS(SL,"Test.unittest",1),"main",0) write(".")
The Cheetah Developers' Guide looks at .py template modules in depth, and shows what the various directives compile to. But you are welcome to take a peek at some .py template modules yourself if you're curious about what Cheetah does under the hood. It's all regular Python code: writing strings and function calls to a file-like object.
Looking at a .py template module may also help you see why something doesn't work, by seeing what Cheetah thought you meant. It also helps discourage you from modifying the .py file yourself, because who wants to keep all those function calls and arguments straight? Let the computer do the drudgery work.
In addition to importing your .py template module file into a Python script or using it as a Webware servlet, you can also run it from the command line as a standalone program. The program will print the filled template on standard output. This is useful while debugging the template, and for producing formatted output in shell scripts.
When running the template as a program, you cannot provide a searchList or
set self.
attributes in the normal way, so you must take
alternative measures to ensure that every placeholder has a value.
Otherwise, you will get the usual NameMapper.NotFound
exception at
the first missing value. You can either set default values in the template
itself (via the #attr
or #def
directives) or in a Python
superclass, or use the --env
or --pickle
command-line options,
which work just like their ``cheetah fill'' counterparts.
Run python FILENAME.py --help
to see all the command-line
options your .py template module accepts.
Because Cheetah documents are actually class definitions, templates may inherit from one another in a natural way, using regular Python semantics. For instance, consider this template, FrogBase.tmpl:
#def title This document has not defined its title #end def #def htTitle $title #end def <HTML><HEAD> <TITLE>$title</TITLE> </HEAD><BODY> <H1>$htTitle</H1> $body </BODY></HTML>
And its subclassed document, Frog1.tmpl:
#from FrogBase import FrogBase #extends FrogBase #def title The Frog Page #end def #def htTitle The <IMG SRC="Frog.png"> page #end def #def body ... lots of info about frogs ... #end def
This is a classic use of inheritance. The parent ``template'' is simply an
abstract superclass. Each document specializes the output of its parent.
For instance, here the parent defines
$htTitle
so that by default it's identical to whatever the
$title
is, but it can also be customized.
In many other templating systems, you'd have to use case statements or if-elseif blocks of some sort, repeated in many different sections of code.
While we show another Cheetah document inheriting from this parent, a Python
class can inherit from it just as easily. This Python class could define its
programmatically-driven value for $body
and $title
, simply by
defining body() and title() methods that return a string. (Actually they
can return anything, but we'll get into that later.)
from FrogBase import FrogBase class Frog2(FrogBase): def title(self): return "Frog 2 Page" # We don't override .htTitle, so it defaults to "Frog 2 Page" too. def body(self): return " ... more info about frogs ..."
Similarly, the Cheetah document can inherit from an arbitrary class. That's
how Cheetah makes templates usable as Webware servlets, by subclassing
Servlet
. This technique should be possible for non-Webware systems
too.
(Note: FrogBase.tmpl
could be improved by using the
#block
directive, section 8.8.)
Cheetah's basic syntax was inspired by the Java-based template engines Velocity and WebMacro. It has two types of tags: $placeholders and #directives. Both types are case-sensitive.
Placeholder tags begin with a dollar sign ($varName
) and are similar to
data fields in a form letter or to the %(key)s
fields on the left side
of Python's %
operator. When the template is filled, the placeholders
are replaced with the values they refer to.
Directive tags begin with a hash character (#) and are used for comments, loops, conditional blocks, includes, and all other advanced features. (Note: you can customize the start and end delimeters for placeholder and directive tags, but in this Guide we'll assume you're using the default.)
Placeholders and directives can be escaped by putting a backslash before them.
\$var
and \#if
will be output as literal text.
A placeholder or directive can span multiple physical lines, following the same
rules as Python source code: put a backslash (\
) at the end of all
lines except the last line. However, if there's an unclosed parenthesis,
bracket or brace pending, you don't need the backslash.
#if $this_is_a_very_long_line and $has_lots_of_conditions \ and $more_conditions: <H1>bla</H1> #end if #if $country in ('Argentina', 'Uruguay', 'Peru', 'Colombia', 'Costa Rica', 'Venezuela', 'Mexico') <H1>Hola, senorita!</H1> #else <H1>Hey, baby!</H1> #end if
## single line
#* multi line *#
$placeholder
#echo
...
#silent
...
#if EXPR then EXPR else EXPR
#slurp
#include
...
#include raw
...
#raw
...#end raw
$*var
, $*<interval>*var
#cache
...#end cache
#filter
...
#indent
...(not
implemented yet)
#import
...,
#from
...
#extends
#implements
...
#attr
...
#def
...#end def
#block
...#end block
provides a simplified
interface to #def
...#end def
#set
...
#set global
...
#del
...
#if
...#else
...#else if
(aka
#elif
) ...#end if
#unless
...#end unless
#for
...#end for
#repeat
...#end repeat
#while
...#end while
#break
#continue
#pass
#stop
#assert
#raise
#try
...#except
...#else
...
#end try
#try
...#finally
...#end try
#errorCatcher
...set a handler for exceptions raised by
$placeholder calls.
#breakpoint
#compiler-settings
...#end compiler-settings
<%=
...
%>
<%
...%>
#encoding
#shBang
The use of all these constructs will be covered in the next several chapters.
$
(the short form) or enclosed in
${}
(the long form).
Examples:
$var ${var} $var2.abc['def']('gh', $subplaceholder, 2) ${var2.abc['def']('gh', $subplaceholder, 2)}
$
in simple cases, and ${}
when followed
directly by a letter or when Cheetah or a human template maintainer might
get confused about where the placeholder ends. You may alternately use
$()
or $[]
, although this may confuse the (human) template
maintainer:
$(var) $[var] $(var2.abc['def']('gh', $subplaceholder, 2)) $[var2.abc['def']('gh', $subplaceholder, 2)]
#compiler
directive.
Note 2: The long form can be used only with top-level placeholders, not in expressions. See section 5.3 for an elaboration on this.
()
and/or keys/subscripts in []
.
$var
does not equal $Var
or $vAr
or $VAR
.
()
or []
are just like in Python.
Strings may be quoted using any Python quoting style. Each argument is an
expression and may use any of Python's expression operators. Variables
used in argument expressions are placeholders and should be prefixed with
$
. This also applies to the *arg and **kw forms. However, you do
not need the $
with the special Python constants None
,
True
and False
.
Examples:
$hex($myVar) $func($arg=1234) $func2($*args, $**kw) $func3(3.14159, $arg2, None, True) $myList[$mySubscript]
$varName.
is varName
, and the period will be left
alone in the template output.
${placeholderName, arg1="val1"}
passes arguments to
the output filter (see #filter
, section 7.9.
The braces and comma are required in this case. It's conventional to
omit the $
before the keyword arguments (i.e. arg1
) in this
case.
$
) that are not followed by a
letter or an underscore.
The following are valid $placeholders:
$a $_ $var $_var $var1 $_1var $var2_ $dict.key $list[3] $object.method $object.method() $object.method $nest($nest($var))
These are not $placeholders but are treated as literal text:
$@var $^var $15.50 $$
There are three places you can use placeholders: top-level position, expression position and LVALUE position. Each has slightly different syntax rules.
Top-level position means interspersed in text. This is the only place
you can use the placeholder long form: ${var}
.
Expression position means inside a Cheetah expression, which is the same as a Python expression. The placeholder names a searchList or other variable to be read. Expression position occurs inside () and arguments within placeholder tags (i.e., a placeholder inside a placeholder), and in several directive tags.
LVALUE position means naming a variable that will be written to. LVALUE
is a computer science term meaning ``the left side of an assignment
statement''. The first argument of directives #set
, #for
,
#def
, #block
and #attr
is an LVALUE.
This stupid example shows the three positions. Top-level position is shown
in courier
, expression position is italic, and LVALUE position is
bold.
#for $count in $range($ninetyNine, 0, -1)
#set $after = $count - 1$count
bottles of beer on the wall.$count
bottles of beer!
Take one down, pass it around.$after
bottles of beer on the wall.
#end for$hex
($myVar, $default=None)
The output of course is:
99 bottles of beer on the wall. 99 bottles of beer! Take one down, pass it around. 98 bottles of beer on the wall. 98 bottles of beer on the wall. 98 bottles of beer! Take one down, pass it around. 97 bottles of beer on the wall. ...
$
is a ``smart variable prefix''. When Cheetah sees $
, it
determines both the variable's position and whether it's a searchList value or
a non-searchList value, and generates the appropriate Python code.
In top-level position, the $
is required. Otherwise there's
nothing to distinguish the variable from ordinary text, and the variable name
is output verbatim.
In expression position, the $
is required if the value comes from
the searchList or a ``#set global'' variable, recommended for
local/global/builtin variables, and not necessary for the special
constants None
, True
and False
. This works because
Cheetah generates a function call for a searchList placeholder, but a bare
variable name for a local/global/builtin variable.
In LVALUE position, the $
is recommended. Cheetah knows where
an LVALUE is expected, so it can handle your variable name whether it has
$
or not.
EXCEPTION: Do not use the $
prefix for intermediate variables in
a Python list comprehensions. This is a limitation of Cheetah's parser; it
can't tell which variables in a list comprehension are the intermediate
variables, so you have to help it. For example:
#set $theRange = [x ** 2 for x in $range(10)]
$theRange
is a regular #set
variable. $range
is a
Python built-in function. But x
is a scratch variable internal to
the list comprehension: if you type $x
, Cheetah will miscompile
it.
One of our core aims for Cheetah was to make it easy for non-programmers to use. Therefore, Cheetah uses a simplified syntax for mapping placeholders in Cheetah to values in Python. It's known as the NameMapper syntax and allows for non-programmers to use Cheetah without knowing (a) the difference between an instance and a dictionary, (b) what functions and methods are, and (c) what 'self' is. A side benefit is that you can change the underlying data structure (e.g., instance to dictionary or vice-versa) without having to modify the templates.
NameMapper syntax is used for all variables in Cheetah placeholders and
directives. If desired, it can be turned off via the Template
class'
'useNameMapper'
compiler setting. But it's doubtful you'd ever want to
turn it off.
Consider this scenario:
You are building a customer information system. The designers with you want to use information from your system on the client's website -AND- they want to understand the display code and so they can maintian it themselves.
You write a UI class with a 'customers' method that returns a dictionary of all the customer objects. Each customer object has an 'address' method that returns the a dictionary with information about the customer's address. The designers want to be able to access that information.
Using PSP, the display code for the website would look something like the following, assuming your servlet subclasses the class you created for managing customer information:
<%= self.customer()[ID].address()['city'] %> (42 chars)
With Cheetah's NameMapper syntax, you can use any of the following:
$self.customers()[$ID].address()['city'] (39 chars) --OR-- $customers()[$ID].address()['city'] --OR-- $customers()[$ID].address().city --OR-- $customers()[$ID].address.city --OR-- $customers[$ID].address.city (27 chars)
Which of these would you prefer to explain to the designers, who have no programming experience? The last form is 15 characters shorter than the PSP version and - conceptually - far more accessible. With PHP or ASP, the code would be even messier than with PSP.
This is a rather extreme example and, of course, you could also just implement
$getCustomer($ID).city
and obey the Law of Demeter (search Google for more
on that). But good object orientated design isn't the point of this example.
NameMapper syntax allows access to dictionary items with the same dotted notation used to access object attributes in Python. This aspect of NameMapper syntax is known as 'Unified Dotted Notation'. For example, with Cheetah it is possible to write:
$customers()['kerr'].address() --OR-- $customers().kerr.address()
This works only with dictionary keys that also happen to be valid Python identifiers.
Cheetah automatically detects functions and methods in Cheetah $variables and calls them if the parentheses have been left off. Our previous example can be further simplified to:
$customers.kerr.address
As another example, if 'a' is an object, 'b' is a method
$a.b
is equivalent to
$a.b()
If b returns a dictionary, then following variations are possible
$a.b.c --OR-- $a.b().c --OR-- $a.b()['c']
Further notes:
self
for methods) or to provide default values for all arguments.
If the function requires arguments, you must use the ()
.
$myInstance.fname
. Do we want to look up fname
in the namespace
of myInstance
or in the namespace of whatever myinstance
returns?
It could go either way, so Cheetah follows the principle of least surprise. If
you do want to call the instance, put the ()
on, or rename the
.__call__()
method to .__str__
.
$getVar('varName', 'default value', False)
. (.getVar()
works
only with searchList values.)
When Cheetah maps a variable name in a template to a Python value, it searches several namespaces in order:
#set
,
#for
, or predefined by Cheetah.
#set global
variables.
Template
constructor, if any.
#def
methods and #block methods
,
attributes/methods inherited via #extends
, and other
attributes/methods built into Template
or inherited by it
(there's a list of all these methods in section
13.5).
#import
,
#from ... import
, or otherwise predefined by Cheetah.
None
, max
, etc.
The first matching name found is used.
Remember, these namespaces apply only to the first identifier after the
$
. In a placeholder like $a.b
, only `a' is looked up in the
searchList and other namespaces. `b' is looked up only inside `a'.
A searchList container can be any Python object with attributes or keys: dictionaries, instances, classes or modules. If an instance contains both attributes and keys, its attributes are searched first, then its keys.
Because the Template
instance is part of the searchList, you can
access its attributes/methods without `self': $myAttr
. However, use
the `self' if you want to make sure you're getting the Template
attribute and not a same-name variable defined in a higher namespace:
$self.myAttr
. This works because ``self'' itself is a local variable.
The final resulting value, after all lookups and function calls (but before the filter is applied) is called the placeholder value, no matter which namespace it was found in.
Note carefully: if you put an object `myObject' in the searchList,
you cannot look up $myObject
! You can look up only the
attributes/keys inside `myObject'.
Earlier versions of Cheetah did not allow you to override Python builtin names, but this was fixed in Cheetah 0.9.15.
If your template will be used as a Webware servlet, do not override methods
'name' and 'log' in the Template
instance or it will interfere with
Webware's logging. However, it is OK to use those variables in a higher
namespace, since Webware doesn't know about Cheetah namespaces.
If NameMapper can not find a Python value for a Cheetah variable name, it will
raise the NameMapper.NotFound exception. You can use the #errorCatcher
directive (section 10.2) or errorCatcher
Template constructor argument (section 4.1) to specify
an alternate behaviour. BUT BE AWARE THAT errorCatcher IS ONLY INTENDED FOR
DEBUGGING!
To provide a default value for a placeholder, write it like this:
$getVar('varName', 'default value')
. If you don't specify a default
and the variable is missing, NameMapper.NotFound
will be raised.
Directive tags begin with a hash character (#) and are used for comments,
loops, conditional blocks, includes, and all other advanced features. Cheetah
uses a Python-like syntax inside directive tags and understands any valid
Python expression. However, unlike Python, Cheetah does not use colons
(:) and indentation to mark off multi-line directives. That doesn't work in
an environment where whitespace is significant as part of the text. Instead,
multi-line directives like #for
have corresponding closing tags
(#end for
). Most directives are direct mirrors of Python statements.
Many directives have arguments after the opening tag, which must be in the specified syntax for the tag. All end tags have the following syntax:
#end TAG_NAME [EXPR]
#
, or implicitly with the
end of the line if you're feeling lazy.
#block testBlock # Text in the body of the block directive #end block testBlock #
#block testBlock Text in the body of the block directive #end block testBlock
When a directive tag is closed explicitly, it can be followed with other text on the same line:
bah, bah, #if $sheep.color == 'black'# black#end if # sheep.
When a directive tag is closed implicitly with the end of the line, all trailing whitespace is gobbled, including the newline character:
""" foo #set $x = 2 bar """ outputs """ foo bar """ while """ foo #set $x = 2 # bar """ outputs """ foo bar """
When a directive tag is closed implicitly AND there is no other text on the line, the ENTIRE line is gobbled up including any preceeding whitespace:
""" foo #set $x = 2 bar """ outputs """ foo bar """ while """ foo - #set $x = 2 bar """ outputs """ foo - bar """
The #slurp
directive (section 7.7) also gobbles up
whitespace.
Spaces outside directives are output exactly as written. In the black sheep example, there's a space before ``black'' and another before ``sheep''. So although it's legal to put multiple directives on one line, it can be hard to read.
#if $a# #echo $a + 1# #end if - There's a space between each directive, or two extra spaces total. #if $a##echo $a + 1##end if - No spaces, but you have to look closely to verify none of the ``##'' are comment markers. #if $a##echo $a + 1##end if ### A comment. - In ``###'', the first ``#'' ends the directive, the other two begin the comment. (This also shows how you can add extra whitespace in the directive tag without affecting the output.) #if $a##echo $a + 1##end if # ## A comment. - More readable, but now there's a space before the comment.
Comments are used to mark notes, explanations, and decorative text that should not appear in the output. Cheetah maintains the comments in the Python module it generates from the Cheetah source code. There are two forms of the comment directive: single-line and multi-line.
All text in a template definition that lies between two hash characters
(##
) and the end of the line is treated as a single-line comment and
will not show up in the output, unless the two hash characters are escaped with
a backslash.
##============================= this is a decorative comment-bar $var ## this is an end-of-line comment ##=============================
Any text between #*
and *#
will be treated as a multi-line
comment.
#* Here is some multiline comment text *#
If you put blank lines around method definitions or loops to separate them, be aware that the blank lines will be output as is. To avoid this, make sure the blank lines are enclosed in a comment. Since you normally have a comment before the next method definition (right?), you can just extend that comment to include the blank lines after the previous method definition, like so:
#def method1 ... lines ... #end def #* Description of method2. $arg1, string, a phrase. *# #def method2($arg1) ... lines ... #end def
Python modules, classes, and methods can be documented with inline 'documentation strings' (aka 'docstrings'). Docstrings, unlike comments, are accesible at run-time. Thus, they provide a useful hook for interactive help utilities.
Cheetah comments can be transformed into doctrings by adding one of the following prefixes:
##doc: This text will be added to the method docstring #*doc: If your template file is MyTemplate.tmpl, running "cheetah compile" on it will produce MyTemplate.py, with a class MyTemplate in it, containing a method .respond(). This text will be in the .respond() method's docstring. *# ##doc-method: This text will also be added to .respond()'s docstring #*doc-method: This text will also be added to .respond()'s docstring *# ##doc-class: This text will be added to the MyTemplate class docstring #*doc-class: This text will be added to the MyTemplate class docstring *# ##doc-module: This text will be added to the module docstring MyTemplate.py #*doc-module: This text will be added to the module docstring MyTemplate.py*#
##header: This text will be added to the module header comment #*header: This text will be added to the module header comment *#
Note the difference between ##doc-module:
and header:
:
``cheetah-compile'' puts ##doc-module:
text inside the module
docstring. header:
makes the text go above the docstring, as a
set of #-prefixed comment lines.
Syntax:
#echo EXPR
The #echo
directive is used to echo the output from expressions that
can't be written as simple $placeholders.
Here is my #echo ', '.join(['silly']*5) # example
This produces:
Here is my silly, silly, silly, silly, silly example.
Syntax:
#silent EXPR
#silent
is the opposite of #echo
. It executes an expression
but discards the output.
#silent $myList.reverse() #silent $myList.sort() Here is #silent $covertOperation() # nothing
If your template requires some Python code to be executed at the beginning;
(e.g., to calculate placeholder values, access a database, etc), you can put
it in a "doEverything" method you inherit, and call this method using
#silent
at the top of the template.
Syntax:
#if EXPR1 then EXPR2 else EXPR3#
The #if
flow-control directive (section 9.4) has a
one-line counterpart akin to Perl's and C's ?:
operator.
If EXPR1
is true, it evaluates EXPR2
and outputs the result (just
like #echo EXPR2#
). Otherwise it evaluates EXPR3
and outputs
that result. This directive is short-circuiting, meaning the expression that
isn't needed isn't evaluated.
You MUST include both 'then' and 'else'. If this doesn't work for you or you
don't like the style use multi-line #if
directives (section
9.4).
The trailing #
is the normal end-of-directive character. As usual
it may be omitted if there's nothing after the directive on the same line.
By default, the values of each $placeholder is retrieved and interpolated for every request. However, it's possible to cache the values of individual placeholders if they don't change very often, in order to speed up the template filling.
To cache the value of a single $placeholder
, add an asterisk after the
$; e.g., $*var
. The first time the template is
filled, $var
is looked up. Then whenever the template is filled again,
the cached value is used instead of doing another lookup.
The $*
format caches ``forever''; that is, as long as the template
instance remains in memory. It's also possible to cache for a certain time
period using the form $*<interval>*variable
, where <interval>
is
the interval. The time interval can be specified in seconds (5s), minutes
(15m), hours (3h), days (2d) or weeks (1.5w). The default is minutes.
<HTML> <HEAD><TITLE>$title</TITLE></HEAD> <BODY> $var ${var} ## dynamic - will be reinterpolated for each request $*var2 $*{var2} ## static - will be interpolated only once at start-up $*5*var3 $*5*{var3} ## timed refresh - will be updated every five minutes. </BODY> </HTML>
Note that ``every five minutes'' in the example really means every five minutes: the variable is looked up again when the time limit is reached, whether the template is being filled that frequently or not. Keep this in mind when setting refresh times for CPU-intensive or I/O intensive operations.
If you're using the long placeholder syntax, ${}
, the braces go only
around the placeholder name: $*.5h*{var.func('arg')}
.
Sometimes it's preferable to explicitly invalidate a cached item whenever you say so rather than at certain time intervals. You can't do this with individual placeholders, but you can do it with cached regions, which will be described next.
Syntax:
#cache [id=EXPR] [timer=EXPR] [test=EXPR] #end cache
The #cache
directive is used to cache a region of
content in a template. The region is cached as a single unit, after
placeholders and directives inside the region have been evaluated. If there
are any $*<interval>*var
placholders inside the cache
region, they are refreshed only when both the cache region and the
placeholder are simultaneously due for a refresh.
Caching regions offers more flexibility than caching individual placeholders. You can specify the refresh interval using a placeholder or expression, or refresh according to other criteria rather than a certain time interval.
#cache
without arguments caches the region statically, the same
way as $*var
. The region will not be automatically refreshed.
To refresh the region at an interval, use the timer=EXPRESSION
argument,
equivalent to $*<interval>*
. 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.
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 <PRE>
tag and LaTeX's
tag, but unlike those tags,
verbatim{}#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.
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"
And this example demonstrates use with $placeholder
variables:
#include source=$myParseText
$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.)
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
0 1 2 3 4
This directive is not implemented yet. When/if it's completed, it will allow you to
#if
blocks) without affecting the output
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.
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
str(whateverItIs)
. This is the base class for all other filters,
and the minimum behaviour for all filters distributed with Cheetah.
ReplaceNone
MaxLen
Pager
WebSafe
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.
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.
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.
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 "<HTML><HEAD>...", 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.
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?''
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
#set $adj = $size > 1500 and 'large' or 'small'
#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.
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.
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):
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
#def myMeth2 This is the $adj method #end def
#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.
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.
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:
<TABLE> #for $client in $service.clients <TR> <TD>$client.surname, $client.firstname</TD> <TD><A HREF="mailto:$client.email" >$client.email</A></TD> </TR> #end for </TABLE>
Here's how to loop through the keys and values of a dictionary:
<PRE> #for $key, $value in $dict.items() $key: $value #end for </PRE>
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)
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
.
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.
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 <table> <tr> <th>Name</th> <th>Address</th> <th>Phone</th> </tr> #for $p in $people <tr> <td>$p.name</td> <td>$p.address</td> <td>$p.phone</td> </tr> #end for </table> #else <p> Sorry, the search did not find any people. </p> #end if
See section 7.3 for the one-line #if
directive,
which is equivalent to Perl's and C's ?:
operator.
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.
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
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
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.
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
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.
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.
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.
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.
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:
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.
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
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.
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')
#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)
$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.
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" )
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.
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 ... ===========================================================================
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.
.__init__
.
None
if no compilation took place.
None
if no compilation took place.
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.
$varName
but allows you to
specify a default value and control whether autocalling occurs.
#include raw
. If used in an expression,
returns the file's content (e.g., to assign it to a variable).
.webInput
.
#compiler-settings
, section
11.2.
copy
module.
name=value
pairs rather
than a dictionary, the same as you would provide in a
#compiler-settings
directive, section
11.2.
cheetahVarStartToken = "@"
).
ConfigParser
module.
Do not override these in a subclass or assign to them as attributes if your template will be used as a servlet, otherwise Webware will behave unpredictably. However, it is OK to put same-name variables in the searchList, because Webware does not use the searchList.
EXCEPTION: It's OK to override awake and sleep as long as you call the superclass methods. (See section 13.4.)
Several other goodies are available to template-servlets under the
request
attribute, see section 14.7.
transaction
, response
, request
and session
are
created from the current transaction when WebKit calls awake
, and don't
exist otherwise. Calling awake
yourself (rather than letting WebKit
call it) will raise an exception because the transaction
argument won't
have the right attributes.
The same caveats about overriding these methods apply.
.serverSidePath()
.
Here are some things you can do to make your templates fill faster and user fewer CPU cycles. Before you put a lot of energy into this, however, make sure you really need to. In many situations, templates appear to initialize and fill instantaneously, so no optimization is necessary. If you do find a situation where your templates are filling slowly or taking too much memory or too many CPU cycles, we'd like to hear about it on the mailing list.
Cache $placeholders whose values don't change frequently. (Section 7.4).
Use #set
for values that are very frequently used, especially if they
come out of an expensive operation like a deeply.nested.structure or a database
lookup. #set
variables are set to Python local variables, which have a
faster lookup time than Python globals or values from Cheetah's searchList.
Moving variable lookups into Python code may provide a speedup in certain
circumstances. If you're just reading self
attributes, there's no
reason to use NameMapper lookup ($placeholders) for them. NameMapper does
a lot more work than simply looking up a self
attribute.
On the other hand, if you don't know exactly where the value will come from
(maybe from self
, maybe from the searchList, maybe from a CGI input
variable, etc), it's easier to just make that an argument to your method, and
then the template can handle all the NameMapper lookups for you:
#silent $myMethod($arg1, $arg2, $arg3)
self.getVar('arg1')
etc in your
method, which is more wordy, and tedious.
<%= ...%>
and <% ...%>
allow an escape
to Python syntax inside the template. You do not need it to use Cheetah
effectively, and we're hard pressed to think of a case to recommend it.
Nevertheless, it's there in case you encounter a situation you can't
express adequately in Cheetah syntax. For instance, to set a local
variable to an elaborate initializer.
<%= ...%>
encloses a Python expression whose result will
be printed in the output.
<% ...%>
encloses a Python statement or expression (or set of
statements or expressions) that will be included as-is into the generated
method. The statements themselves won't produce any output, but you can use
the local function write(EXPRESSION)
to produce your own output.
(Actually, it's a method of a file-like object, but it looks like a local
function.) This syntax also may be used to set a local variable with a
complicated initializer.
To access Cheetah services, you must use Python code like you would in an
inherited Python class. For instance, use self.getVar()
to look up
something in the searchList.
Warning: No error checking is done! If you write:
<% break %> ## Wrong!
SyntaxError
when you fill the template, but that's what you
deserve.
Note that these are PSP-style tags, not PSP tags. A Cheetah template is not a PSP document, and you can't use PSP commands in it.
If your project has several templates and you get sick of typing
``cheetah compile FILENAME.tmpl'' all the time-much less remembering which
commands to type when-and your system has the make
command available, consider building a Makefile to make your life easier.
Here's a simple Makefile that controls two templates, ErrorsTemplate and
InquiryTemplate. Two external commands, inquiry
and receive
,
depend on ErrorsTemplate.py. Aditionally, InquiryTemplate
itself depends on ErrorsTemplate.
all: inquiry receive .PHONY: all receive inquiry printsource printsource: a2ps InquiryTemplate.tmpl ErrorsTemplate.tmpl ErrorsTemplate.py: ErrorsTemplate.tmpl cheetah compile ErrorsTemplate.tmpl InquiryTemplate.py: InquiryTemplate.tmpl ErrorsTemplate.py cheetah compile InquiryTemplate.tmpl inquiry: InquiryTemplate.py ErrorsTemplate.py receive: ErrorsTemplate.py
Now you can type make
anytime and it will recompile all the templates
that have changed, while ignoring the ones that haven't. Or you can
recompile all the templates receive
needs by typing make receive
.
Or you can recompile only ErrorsTemplate by typing
make ErrorsTemplate
. There's also another target, ``printsource'':
this sends a Postscript version of the project's source files to the printer.
The .PHONY target is explained in the make
documentation; essentially,
you have it depend on every target that doesn't produce an output file with
the same name as the target.
Template classes may be shared freely between threads. However, template instances should not be shared unless you either:
$*var
, #cache
, etc).
#set global
, #filter
, #errorCatcher
.
About the only advantage in sharing a template instance is building up the
placeholder cache. But template instances are so low overhead that it
probably wouldn't take perceptibly longer to let each thread instantiate its
own template instance. Only if you're filling templates several times a
second would the time difference be significant, or if some of the placeholders
trigger extremely slow calculations (e.g., parsing a long text file each time).
The biggest overhead in Cheetah is importing the Template
module in
the first place, but that has to be done only once in a long-running
application.
You can use Python's mutex
module for the lock, or any similar
mutex. If you have to change searchList values or instance variables
before each fill (which is usually the case), lock the mutex before
doing this, and unlock it only after the fill is complete.
For Webware servlets, you're probably better off using Webware's servlet
caching rather than Cheetah's caching. Don't override the servlet's
.canBeThreaded()
method unless you avoid the unsafe operations
listed above.
gettext is a project for creating internationalized applications. For more details, visit http://docs.python.org/lib/module-gettext.html. gettext can be used with Cheetah to create internationalized applications, even for CJK character sets, but you must keep a couple things in mind:
_
, N_
, and ngettext
. If you need to use a
different set of functions for marking strings for translation, you must set
the Cheetah setting gettextTokens
to a list of strings representing the
names of the functions you are using to mark strings for translation.
Webware for Python is a 'Python-Powered Internet Platform' that runs servlets in a manner similar to Java servlets. WebKit is the name of Webware's application server. For more details, please visit http://webware.sourceforge.net/.
All comments below refer to the official version of Webware, the DamnSimple!
offshoot at ?, and the now-abandoned WebwareExperimental implementation at
http://sourceforge.net/projects/expwebware/, except where noted. All the
implementations are 95% identical to the servlet writer: their differences lie
in their internal structure and configuration files. One difference is that
the executable you run to launch standard Webware is called AppServer
,
whereas in WebwareExperimental it's called webkit
. But to servlets
they're both "WebKit, Webware's application server", so it's one half dozen to
the other. In this document, we generally use the term WebKit to refer
to the currently-running application server.
Install Cheetah after you have installed Webware, following the instructions in chapter 3.
The standard Cheetah test suite ('cheetah test') does not test Webware features. We plan to build a test suite that can run as a Webware servlet, containing Webware-specific tests, but that has not been built yet. In the meantime, you can make a simple template containing something like "This is a very small template.", compile it, put the *.py template module in a servlet directory, and see if Webware serves it up OK.
You must not have a Webware context called "Cheetah". If you do, Webware will mistake that directory for the Cheetah module directory, and all template-servlets will bomb out with a "ImportError: no module named Template". (This applies only to the standard Webware; WebwareExperimental does not have contexts.)
If Webware complains that it cannot find your servlet, make sure '.tmpl' is listed in 'ExtensionsToIgnore' in your 'Application.config' file.
Because Cheetah's core is flexible, there are many ways to integrate it with
Webware servlets. There are two broad strategies: the Inheritance
approach and the Containment approach. The difference is
that in the Inheritance approach, your template object is
the
servlet, whereas in the Containment approach, the servlet is not a template but
merely uses template(s) for portion(s) of its work.
The Inheritance approach is recommended for new sites because it's simpler, and because it scales well for large sites with a site->section->subsection->servlet hierarchy. The Containment approach is better for existing servlets that you don't want to restructure. For instance, you can use the Containment approach to embed a discussion-forum table at the bottom of a web page.
However, most people who use Cheetah extensively seem to prefer the Inheritance approach because even the most analytical servlet needs to produce some output, and it has to fit the site's look and feel anyway, so you may as well use a template-servlet as the place to put the output. Especially since it's so easy to add a template-servlet to a site once the framework is established. So we recommend you at least evaluate the effort that would be required to convert your site framework to template superclasses as described below, vs the greater flexibility and manageability it might give the site over the long term. You don't necessarily have to convert all your existing servlets right away: just build common site templates that are visually and behaviorally compatible with your specification, and use them for new servlets. Existing servlets can be converted later, if at all.
Edmund Liam is preparing a section on a hybrid approach, in which the
servlet is not a template, but still calls template(s) in an inheritance
chain to produce the output. The advantage of this approach is that you
aren't dealing with Template
methods and Webware methods in the
same object.
In the Containment approach, your servlet is not a template. Instead, it
it makes its own arrangements to create and use template object(s) for whatever
it needs. The servlet must explicitly call the template objects'
.respond()
(or .__str__()
) method each time it needs to fill
the template. This does not present the output to the user; it merely gives
the output to the servlet. The servlet then calls its
#self.response().write()
method to send the output to the user.
The developer has several choices for managing her templates. She can store the
template definition in a string, file or database and call
Cheetah.Template.Template
manually on it. Or she can put the
template definition in a *.tmpl file and use cheetah compile (section
4.2) to convert it to a Python class in a *.py
module, and then import it into her servlet.
Because template objects are not thread safe, you should not store one in a module variable and allow multiple servlets to fill it simultaneously. Instead, each servlet should instantiate its own template object. Template classes, however, are thread safe, since they don't change once created. So it's safe to store a template class in a module global variable.
In the Inheritance approach, your template object doubles as as Webware
servlet, thus these are sometimes called template-servlets. cheetah
compile (section 4.2) automatically creates modules
containing valid Webware servlets. A servlet is a subclass of Webware's
WebKit.HTTPServlet
class, contained in a module with the same name as
the servlet. WebKit uses the request URL to find the module, and then
instantiates the servlet/template. The servlet must have a .respond()
method (or .respondToGet()
, .respondToPut()
, etc., but the
Cheetah default is .respond()
). Servlets created by cheetah
compile
meet all these requirements.
(Cheetah has a Webware plugin that automatically converts a .tmpl servlet
file
into a .py servlet file
when the .tmpl servlet file
is
requested by a browser. However, that plugin is currently unavailable because
it's being redesigned. For now, use cheetah compile
instead.)
What about logic code? Cheetah promises to keep content (the placeholder values), graphic design (the template definition and is display logic), and algorithmic logic (complex calculations and side effects) separate. How? Where do you do form processing?
The answer is that your template class can inherit from a pure Python class
containing the analytical logic. You can either use the #extends
directive in Cheetah to indicate the superclass(es), or write a Python
class
statement to do the same thing. See the template
Cheetah.Templates.SkeletonPage.tmpl
and its pure Python class
Cheetah.Templates._SkeletonPage.py
for an example of a template
inheriting logic code. (See sections 8.2 and
8.3 for more information about #extends
and
#implements
. They have to be used a certain right way.)
If #WebKit.HTTPServlet
is not available, Cheetah fakes it with a
dummy class to satisfy the dependency. This allows servlets to be tested on
the command line even on systems where Webware is not installed. This works
only with servlets that don't call back into WebKit for information about the
current web transaction, since there is no web transaction. Trying to access
form input, for instance, will raise an exception because it depends on a
live web request object, and in the dummy class the request object is
None
.
Because Webware servlets must be valid Python modules, and ``cheetah compile'' can produce only valid module names, if you're converting an existing site that has .html filenames with hyphens (-), extra dots (.), etc, you'll have to rename them (and possibly use redirects).
Web sites are normally arranged hierarchically, with certain features common to every page on the site, other features common to certain sections or subsections, and others unique to each page. You can model this easily with a hierarchy of classes, with specific servlets inheriting from their more general superclasses. Again, you can do this two ways, using Cheetah's Containment approach or Inheritance approach.
In the Inheritance approach, parents provide #block
s and children
override them using #def
. Each child #extend
s its immediate
parent. Only the leaf servlets need to be under WebKit's document root
directory. The superclass servlets can live anywhere in the filesystem
that's in the Python path. (You may want to modify your WebKit startup
script to add that library directory to your PYTHONPATH
before starting
WebKit.)
Section 17.7 contains information on a stock template that simplifies defining the basic HTML structure of your web page templates.
In the Containment approach, your hierarchy of servlets are not templates, but
each uses one or more templates as it wishes. Children provide callback
methods to to produce the various portions of the page that are their
responsibility, and parents call those methods. Webware's WebKit.Page
and WebKit.SidebarPage
classes operate like this.
Note that the two approaches are not compatible! WebKit.Page
was not
designed to intermix with Cheetah.Templates.SkeletonPage
. Choose either
one or the other, or expect to do some integration work.
If you come up with a different strategy you think is worth noting in this chapter, let us know.
Here's one way to organize your files for Webware+Cheetah.
www/ # Web root directory. site1.example.com/ # Site subdirectory. apache/ # Web server document root (for non-servlets). www/ # WebKit document root. index.py # http://site1.example.com/ index.tmpl # Source for above. servlet2.py # http://site1.example.com/servlet2 servlet2.tmpl # Source for above. lib/ # Directory for helper classes. Site.py # Site superclass ("#extends Site"). Site.tmpl # Source for above. Logic.py # Logic class inherited by some template. webkit.config # Configuration file (for WebwareExperimental). Webware/ # Standard Webware's MakeAppWorkDir directory. AppServer # Startup program (for standard Webware). Configs/ # Configuration directory (for standard Webware). Application.config # Configuration file (for standard Webware). site2.example.org/ # Another virtual host on this computer....
If you need a place to initialize variables or do calculations for your
template-servlet, you can put it in an .awake()
method because WebKit
automatically calls that early when processing the web transaction. If you
do override .awake()
, be sure to call the superclass .awake
method. You probably want to do that first so that you have access to the
web transaction data Servlet.awake
provides. You don't have to worry
about whether your parent class has its own .awake
method, just call
it anyway, and somebody up the inheritance chain will respond, or at minimum
Servlet.awake
will respond. Section
13.4 gives examples of how to call a
superclass method.
As an alternative, you can put all your calculations in your own method and
call it near the top of your template. (#silent
, section
7.2).
There are many ways to display and process HTML forms with Cheetah. But basically, all form processing involves two steps.
The second step may involve choosing between several templates to fill (or several servlets to redirect to), or a big if-elif-elif-else construct to display a different portion of the template depending on the situation.
In the oldest web applications, step 1 and step 2 were handled by separate objects. Step 1 was a static HTML file, and step 2 was a CGI script. Frequently, a better strategy is to have a single servlet handle both steps. That way, the servlet has better control over the entire situation, and if the user submits unacceptable data, the servlet can redisplay the form with a "try again" error message at the top and and all the previous input filled in. The servlet can use the presence or absence of certain CGI parameters (e.g., the submit button, or a hidden mode field) to determine which step to take.
One neat way to build a servlet that can handle both the form displaying and form processing is like this:
VALUE=
attribue.
Place another placeholder next to each field, for that field's error
message.
$processFormData
method call.
#extend
s. (Or
if it's a simple method, you can define it in a #def
.) The method
should:
$processFormData
.
$processFormData
.
$processFormData
.
FunFormKit
is a third-party Webware package that makes it easier to
produce forms and handle their logic. It has been successfully been used with
Cheetah. You can download FunFormKit from
http://colorstudy.net/software/funformkit/ and try it out for yourself.
General variable tips that also apply to servlets are in section 13.1.
To look up a CGI GET or POST parameter (with POST overriding):
$request.field('myField') self.request().field('myField')
$request
(aka self.request()
will be None
rather than a Webware
WebKit.Request
object. If you plan to read a lot of CGI parameters,
you may want to put the .fields
method into a local variable for
convenience:
#set $fields = $request.fields $fields.myField
$request
forms are useful only for occasions where you just need one or two simple
request items that going to Python for would be overkill.
To get a cookie or session parameter, subsitute ``cookie'' or ``session'' for ``field'' above. To get a dictionary of all CGI parameters, substitute ``fields'' (ditto for ``cookies''). To verify a field exists, substitute ``hasField'' (ditto for ``hasCookie'').
Other useful request goodies:
## Defined in WebKit.Request $request.field('myField', 'default value') $request.time ## Time this request began in Unix ticks. $request.timeStamp ## Time in human-readable format ('asctime' format). ## Defined in WebKit.HTTPRequest $request.hasField.myField ## Is a CGI parameter defined? $request.fields ## Dictionary of all CGI parameters. $request.cookie.myCookie ## A cookie parameter (also .hasCookie, .cookies). $request.value.myValue ## A field or cookie variable (field overrides) ## (also .hasValue). $request.session.mySessionVar # A session variable. $request.extraURLPath ## URL path components to right of servlet, if any. $request.serverDictionary ## Dict of environmental vars from web server. $request.remoteUser ## Authenticated username. HTTPRequest.py source ## suggests this is broken and always returns None. $request.remoteAddress ## User's IP address (string). $request.remoteName ## User's domain name, or IP address if none. $request.urlPath ## URI of this servlet. $request.urlPathDir ## URI of the directory containing this servlet. $request.serverSidePath ## Absolute path of this servlet on local filesystem. $request.serverURL ## URL of this servlet, without "http://" prefix, ## extra path info or query string. $request.serverURLDir ## URL of this servlet's directory, without "http://". $log("message") ## Put a message in the Webware server log. (If you ## define your own 'log' variable, it will override ## this; use $self.log("message") in that case.
From the method docstring:
def webInput(self, names, namesMulti=(), default='', src='f', defaultInt=0, defaultFloat=0.00, badInt=0, badFloat=0.00, debug=False): This method places the specified GET/POST fields, cookies or session variables into a dictionary, which is both returned and put at the beginning of the searchList. It handles: * single vs multiple values * conversion to integer or float for specified names * default values/exceptions for missing or bad values * printing a snapshot of all values retrieved for debugging All the 'default*' and 'bad*' arguments have "use or raise" behavior, meaning that if they're a subclass of Exception, they're raised. If they're anything else, that value is substituted for the missing/bad value. The simplest usage is: #silent $webInput(['choice']) $choice dic = self.webInput(['choice']) write(dic['choice']) Both these examples retrieves the GET/POST field 'choice' and print it. If you leave off the "#silent", all the values would be printed too. But a better way to preview the values is #silent $webInput(['name'], $debug=1) because this pretty-prints all the values inside HTML <PRE> tags. Since we didn't specify any coversions, the value is a string. It's a "single" value because we specified it in 'names' rather than 'namesMulti'. Single values work like this: * If one value is found, take it. * If several values are found, choose one arbitrarily and ignore the rest. * If no values are found, use or raise the appropriate 'default*' value. Multi values work like this: * If one value is found, put it in a list. * If several values are found, leave them in a list. * If no values are found, use the empty list ([]). The 'default*' arguments are *not* consulted in this case. Example: assume 'days' came from a set of checkboxes or a multiple combo box on a form, and the user chose "Monday", "Tuesday" and "Thursday". #silent $webInput([], ['days']) The days you chose are: #slurp #for $day in $days $day #slurp #end for dic = self.webInput([], ['days']) write("The days you chose are: ") for day in dic['days']: write(day + " ") Both these examples print: "The days you chose are: Monday Tuesday Thursday". By default, missing strings are replaced by "" and missing/bad numbers by zero. (A "bad number" means the converter raised an exception for it, usually because of non-numeric characters in the value.) This mimics Perl/PHP behavior, and simplifies coding for many applications where missing/bad values *should* be blank/zero. In those relatively few cases where you must distinguish between ""/zero on the one hand and missing/bad on the other, change the appropriate 'default*' and 'bad*' arguments to something like: * None * another constant value * $NonNumericInputError/self.NonNumericInputError * $ValueError/ValueError (NonNumericInputError is defined in this class and is useful for distinguishing between bad input vs a TypeError/ValueError thrown for some other reason.) Here's an example using multiple values to schedule newspaper deliveries. 'checkboxes' comes from a form with checkboxes for all the days of the week. The days the user previously chose are preselected. The user checks/unchecks boxes as desired and presses Submit. The value of 'checkboxes' is a list of checkboxes that were checked when Submit was pressed. Our task now is to turn on the days the user checked, turn off the days he unchecked, and leave on or off the days he didn't change. dic = self.webInput([], ['dayCheckboxes']) wantedDays = dic['dayCheckboxes'] # The days the user checked. for day, on in self.getAllValues(): if not on and wantedDays.has_key(day): self.TurnOn(day) # ... Set a flag or insert a database record ... elif on and not wantedDays.has_key(day): self.TurnOff(day) # ... Unset a flag or delete a database record ... 'source' allows you to look up the variables from a number of different sources: 'f' fields (CGI GET/POST parameters) 'c' cookies 's' session variables 'v' "values", meaning fields or cookies In many forms, you're dealing only with strings, which is why the 'default' argument is third and the numeric arguments are banished to the end. But sometimes you want automatic number conversion, so that you can do numeric comparisons in your templates without having to write a bunch of conversion/exception handling code. Example: #silent $webInput(['name', 'height:int']) $name is $height cm tall. #if $height >= 300 Wow, you're tall! #else Pshaw, you're short. #end if dic = self.webInput(['name', 'height:int']) name = dic[name] height = dic[height] write("%s is %s cm tall." % (name, height)) if height > 300: write("Wow, you're tall!") else: write("Pshaw, you're short.") To convert a value to a number, suffix ":int" or ":float" to the name. The method will search first for a "height:int" variable and then for a "height" variable. (It will be called "height" in the final dictionary.) If a numeric conversion fails, use or raise 'badInt' or 'badFloat'. Missing values work the same way as for strings, except the default is 'defaultInt' or 'defaultFloat' instead of 'default'. If a name represents an uploaded file, the entire file will be read into memory. For more sophisticated file-upload handling, leave that name out of the list and do your own handling, or wait for Cheetah.Utils.UploadFileMixin. This mixin class works only in a subclass that also inherits from Webware's Servlet or HTTPServlet. Otherwise you'll get an AttributeError on 'self.request'. EXCEPTIONS: ValueError if 'source' is not one of the stated characters. TypeError if a conversion suffix is not ":int" or ":float".
If your servlet accesses external files (e.g., via an #include
directive), remember that the current directory is not necessarily directory
the servlet is in. It's probably some other directory WebKit chose. To find a
file relative to the servlet's directory, prefix the path with whatever
self.serverSidePath()
returns (from Servlet.serverSidePath()
.
If you don't understand how #extends
and #implements
work, and
about a template's main method, read the chapter on inheritance (sections
8.2 and 8.3). This may
help you avoid buggy servlets.
Cheetah can be used with all types of HTML output, not just with Webware.
Some sites like Linux Gazette (http://www.linuxgazette.com/) require completely static pages because they are mirrored on servers running completely different software from the main site. Even dynamic sites may have one or two pages that are static for whatever reason, and the site administrator may wish to generate those pages from Cheetah templates.
There's nothing special here. Just create your templates as usual. Then compile and fill them whenever the template definition changes, and fill them again whenever the placeholder values change. You may need an extra step to copy the .html files to their final location. A Makefile (chapter 13.8) can help encapsulate these steps.
Unlike Webware servlets, which don't have to worry about the HTTP headers, CGI scripts must emit their own headers. To make a template CGI aware, add this at the top:
#extends Cheetah.Tools.CGITemplate #implements respond $cgiHeaders#slurp
Or if your template is inheriting from a Python class:
#extends MyPythonClass #implements respond $cgiHeaders#slurp
A sample Python class:
from Cheetah.Tools import CGITemplate class MyPythonClass(CGITemplate): def cgiHeadersHook(self): return "Content-Type: text/html; charset=koi8-r\n\n"
Compile the template as usual, put the .py template module in your
cgi-bin directory and give it execute permission. .cgiHeaders()
is
a ``smart'' method that outputs the headers if the module is called as a
CGI script, or outputs nothing if not. Being ``called as a CGI script''
means the environmental variable REQUEST_METHOD
exists and
self.isControlledByWebKit
is false. If you don't agree with that
definition, override .isCgi()
and provide your own.
The default header is a simple Content-type: text/html\n\n
, which works
with all CGI scripts. If you want to customize the headers (e.g., to
specify the character set), override .cgiHeadersHook()
and return
a string containing all the headers. Don't forget to include the extra
newline at the end of the string: the HTTP protocol requires this empty
line to mark the end of the headers.
To read GET/POST variables from form input, use the .webInput()
method
(section 14.7), or extract them yourself using Python's
cgi
module or your own function. Although .webInput()
was
originally written for Webware servlets, it now handles CGI scripts too. There
are a couple behavioral differences between CGI scripts and Webware servlets
regarding input variables:
cgi
module, believe
REQUEST_METHOD
and recognize either GET variables or
POST variables, not both. Webware servlets, doing additional processing,
ignore REQUEST_METHOD
and recognize both, like PHP does.
src='c'
or
src='s'
. CGI scripts get a RuntimeError
if they try to do
this.
If you keep your .tmpl files in the same directory as your CGI scripts, make
sure they don't have execute permission. Apache at least refuses to serve
files in a ScriptAlias
directory that don't have execute permission.
Cheetah can also output any other text format besides HTML.
To be written. We're in the middle of working on an autoindenter to make it easier to encode Python indentation in a Cheetah template.
Cheetah comes ``batteries included'' with libraries of templates, functions, classes and other objects you can use in your own programs. The different types are listed alphabetically below, followed by a longer description of the SkeletonPage framework. Some of the objects are classes for specific purposes (e.g., filters or error catchers), while others are standalone and can be used without Cheetah.
If you develop any objects which are generally useful for Cheetah sites, please consider posting them on the wiki with an announcement on the mailing list so we can incorporate them into the standard library. That way, all Cheetah users will benefit, and it will encourage others to contribute their objects, which might include something you want.
Module Cheetah.ErrorCatchers
contains error-handling classes suitable for
the #errorCatcher
directive. These are debugging tools that are not
intended for use in production systems. See section
10.2 for a description of the error catchers bundled
with Cheetah.
Module Cheetah.FileUtils
contains generic functions and classes for
doing bulk search-and-replace on several files, and for finding all the files
in a directory hierarchy whose names match a glob pattern.
Module Filters
contains filters suitable for the #Filter
directive. See section 7.9 for a description of the
filters bundled with Cheetah.
The SettingsManager
class in the Cheetah.SettingsManager
module is
a baseclass that provides facilities for managing application settings. It
facilitates the use of user-supplied configuration files to fine tune an
application. A setting is a key/value pair that an application or component
(e.g., a filter, or your own servlets) looks up and treats as a configuration
value to modify its (the component's) behaviour.
SettingsManager is designed to:
.ini style config files
(or strings)
.ini config files
to be extended by settings in
Python src files. If a section contains a setting like
``importSettings=mySettings.py
'', SettingsManager
will merge
all the settings defined in ``mySettings.py
'' with the settings for
that section that are defined in the .ini config file
.
Cheetah uses SettingsManager
to manage its configuration settings.
SettingsManager
might also be useful in your own applications. See the
source code and docstrings in the file src/SettingsManager.py
for more
information.
Package Cheetah.Templates
contains stock templates that you can
either use as is, or extend by using the #def
directive to redefine
specific blocks. Currently, the only template in here is SkeletonPage,
which is described in detail below in section
17.7. (Contributed by Tavis Rudd.)
Package Cheetah.Tools
contains functions and classes contributed by third
parties. Some are Cheetah-specific but others are generic and can be used
standalone. None of them are imported by any other Cheetah component; you can
delete the Tools/ directory and Cheetah will function fine.
Some of the items in Tools/ are experimental and have been placed there just to see how useful they will be, and whether they attract enough users to make refining them worthwhile (the tools, not the users :).
Nothing in Tools/ is guaranteed to be: (A) tested, (B) reliable, (C) immune from being deleted in a future Cheetah version, or (D) immune from backwards-incompatable changes. If you depend on something in Tools/ on a production system, consider making a copy of it outside the Cheetah/ directory so that this version won't be lost when you upgrade Cheetah. Also, learn enough about Python and about the Tool so that you can maintain it and bugfix it if necessary.
If anything in Tools/ is found to be necessary to Cheetah's operation (i.e., if
another Cheetah component starts importing it), it will be moved to the
Cheetah.Utils
package.
Current Tools include:
#for
loops), displaying one
pageful of records at a time (with previous/next links), and printing
summary statistics about the records or the current page. See
MondoReportDoc.txt
in the same directory as the module. Some
features are not implemented yet. MondoReportTest.py
is a test
suite (and it shows there are currently some errors in MondoReport, hmm).
Contributed by Mike Orr.
$form.f1
is a
RecursiveNull object, then $form.f1.anything["you"].might("use")
will resolve to the empty string. You can also put a RecursiveNull
instance at the end of the searchList to convert missing values to ''
rather than raising a NotFound
error or having a (less efficient)
errorCatcher handle it. Of course, maybe you prefer to get a
NotFound
error... Contributed by Ian Bicking.
Package Cheetah.Utils
contains non-Cheetah-specific functions and
classes that are imported by other Cheetah components. Many of these utils can
be used standalone in other applications too.
Current Utils include:
Template
objects, and provides the method, .cgiImport
method
(section
UseOrRaise(thing, errmsg='')
Raise 'thing' if it's a
subclass of Exception, otherwise return it. Useful when one
argument does double duty as a default value or an exception to
throw. Contribyted by Mike Orr.
checkKeywords(dic, legalKeywords, what='argument'
Verifies the dictionary does not contain any keys not listed in
'legalKeywords'. If it does, raise TypeError. Useful for
checking the keyword arguments to a function. Contributed by
Mike Orr.
.uploadFile
method (or three methods) to ``safely'' copy a
form-uploaded file to a local file, to a searchList variable, or return
it. When finished, this will be inherited by Template
, allowing
all templates to do this. If you want this feature, read the docstring
in the source and let us know on the mailing list what you'd like this
method to do. Contributed by Mike Orr.
A stock template class that may be useful for web developers is defined in
the Cheetah.Templates.SkeletonPage
module. The SkeletonPage
template class is generated from the following Cheetah source code:
##doc-module: A Skeleton HTML page template, that provides basic structure and utility methods. ################################################################################ #extends Cheetah.Templates._SkeletonPage #implements respond ################################################################################ #cache id='header' $docType $htmlTag <!-- This document was autogenerated by Cheetah(http://CheetahTemplate.org). Do not edit it directly! Copyright $currentYr - $siteCopyrightName - All Rights Reserved. Feel free to copy any javascript or html you like on this site, provided you remove all links and/or references to $siteDomainName However, please do not copy any content or images without permission. $siteCredits --> #block writeHeadTag <head> <title>$title</title> $metaTags $stylesheetTags $javascriptTags </head> #end block writeHeadTag #end cache header ################# $bodyTag #block writeBody This skeleton page has no flesh. Its body needs to be implemented. #end block writeBody </body> </html>
You can redefine any of the blocks defined in this template by writing a new
template that #extends
SkeletonPage. (As you remember, using
#extends
makes your template implement the .writeBody()
method instead of .respond()
- which happens to be the same method
SkeletonPage expects the page content to be (note the writeBody block in
SkeletonPage).)
#def bodyContents Here's my new body. I've got some flesh on my bones now. #end def bodyContents
All of the $placeholders used in the SkeletonPage
template definition
are attributes or methods of the SkeletonPage
class. You can reimplement
them as you wish in your subclass. Please read the source code of the file
src/Templates/_SkeletonPage.py
before doing so.
You'll need to understand how to use the following methods of the
SkeletonPage
class: $metaTags()
, $stylesheetTags()
,
$javascriptTags()
, and $bodyTag()
. They take the data you
define in various attributes and renders them into HTML tags.
_SkeletonPage.py
.
self._stylesheetLibs
and self._stylesheets
dictionaries.
The keys in self._stylesheets
must be listed in the order that
they should appear in the list self._stylesheetsOrder
, to ensure
that the style rules are defined in the correct order.
self._javascriptTags
and self._javascriptLibs
dictionaries.
Each value in self._javascriptTags
should be a either a code string
to include, or a list containing the JavaScript version number and the code
string. The keys can be anything. The same applies for
self._javascriptLibs
, but the string should be the SRC filename
rather than a code string.
self._bodyTagAttribs
.
The class also provides some convenience methods that can be used as $placeholders in your template definitions:
src
'' argument to a WebKit serverSidePath relative to the
servlet's location. If width and height aren't specified they are
calculated using PIL or ImageMagick if either of these tools are available.
If all your images are stored in a certain directory you can reimplement
this method to append that directory's path to the ``src
'' argument.
Doing so would also insulate your template definitions from changes in your
directory structure.
This chapter is about maintaining Cheetah templates with visual editors, and the tradeoffs between making it friendly to both text editors and visual editors.
Cheetah's main developers do not use visual editors. Tavis uses emacs
;
Mike uses vim
. So our first priority is to make templates easy to
maintain in text editors. In particular, we don't want to add features
like Zope Page Template's
placeholder-value-with-mock-text-for-visual-editors-all-in-an-XML-tag.
The syntax is so verbose it makes for a whole lotta typing just to insert a
simple placeholder, for the benefit of editors we never use. However, as users
identify features which would help their visual editing without making it
harder to maintain templates in a text editor, we're all for it.
As it said in the introduction, Cheetah purposely does not use HTML/XML tags for $placeholders or #directives. That way, when you preview the template in an editor that interprets HTML tags, you'll still see the placeholder and directive source definitions, which provides some ``mock text'' even if it's not the size the final values will be, and allows you to use your imagination to translate how the directive output will look visually in the final.
If your editor has syntax highlighting, turn it on. That makes a big difference in terms of making the template easier to edit. Since no ``Cheetah mode'' has been invented yet, set your highlighting to Perl mode, and at least the directives/placeholders will show up in different colors, although the editor won't reliably guess where the directive/placeholder ends and normal text begins.
See the wiki for more links. (The wiki is also updated more often than this chapter is.)
The Cheetah distribution comes with an 'examples' directory. Browse the files in this directory and its subdirectories for examples of how Cheetah can be used.
Cheetah.Tests
module contains a large number of test cases that can
double as examples of how the Cheetah Language works. To view these cases go
to the base directory of your Cheetah distribution and open the file
Cheetah/Tests/SyntaxAndOutput.py
in a text editor.
This appendix compares Cheetah with various other template/emdedded scripting languages and Internet development frameworks. As Cheetah is similar to Velocity at a superficial level, you may also wish to read comparisons between Velocity and other languages at http://jakarta.apache.org/velocity/ymtd/ymtd.html.
#raw
directive (section 7.5)
#slurp
directive (section 7.7)
For a basic introduction to Velocity, visit http://jakarta.apache.org/velocity.
Velocity is a Java template engine. It's older than Cheetah, has a larger user base, and has better examples and docs at the moment. Cheetah, however, has a number of advantages over Velocity:
VelocityContext context1 = new VelocityContext(); context1.put("name","Velocity"); context1.put("project", "Jakarta"); context1.put("duplicate", "I am in context1");
Cheetah takes a different approach. Rather than require you to manually populate the 'namespace' like Velocity, Cheetah will accept any existing Python object or dictionary AS the 'namespace'. Furthermore, Cheetah allows you to specify a list namespaces that will be searched in sequence to find a varname-to-value mapping. This searchList can be extended at run-time.
If you add a `foo' object to the searchList and the `foo' has an attribute
called 'bar', you can simply type $bar
in the template. If the
second item in the searchList is dictionary 'foofoo' containing
{'spam':1234, 'parrot':666}
, Cheetah will first look in the `foo'
object for a `spam' attribute. Not finding it, Cheetah will then go to
`foofoo' (the second element in the searchList) and look among its
dictionary keys for `spam'. Finding it, Cheetah will select
foofoo['spam']
as $spam
's value.
For a basic introduction to WebMacro, visit http://webmacro.org.
The points discussed in section C.2 also apply to the comparison between Cheetah and WebMacro. For further differences please refer to http://jakarta.apache.org/velocity/differences.html.
For a basic introduction to DTML, visit http://www.zope.org/Members/michel/ZB/DTML.dtml.
#raw
directive.
Here are some examples of syntax differences between DTML and Cheetah:
<ul> <dtml-in frogQuery> <li><dtml-var animal_name></li> </dtml-in> </ul>
<ul> #for $animal_name in $frogQuery <li>$animal_name</li> #end for </ul>
<dtml-if expr="monkeys > monkey_limit"> <p>There are too many monkeys!</p> <dtml-elif expr="monkeys < minimum_monkeys"> <p>There aren't enough monkeys!</p> <dtml-else> <p>There are just enough monkeys.</p> </dtml-if>
#if $monkeys > $monkey_limit <p>There are too many monkeys!</p> #else if $monkeys < $minimum_monkeys <p>There aren't enough monkeys!</p> #else <p>There are just enough monkeys.</p> #end if
<table> <dtml-in expr="objectValues('File')"> <dtml-if sequence-even> <tr bgcolor="grey"> <dtml-else> <tr> </dtml-if> <td> <a href="&dtml-absolute_url;"><dtml-var title_or_id></a> </td></tr> </dtml-in> </table>
<table> #set $evenRow = 0 #for $file in $files('File') #if $evenRow <tr bgcolor="grey"> #set $evenRow = 0 #else <tr> #set $evenRow = 1 #end if <td> <a href="$file.absolute_url">$file.title_or_id</a> </td></tr> #end for </table>
The last example changed the name of $objectValues
to
$files
because that's what a Cheetah developer would write.
The developer would be responsible for ensuring $files
returned a
list (or tuple) of objects (or dictionaries) containing the attributes (or
methods or dictionary keys) `absolute_url' and `title_or_id'. All these
names (`objectValues', `absolute_url' and `title_or_id') are standard parts
of Zope, but in Cheetah the developer is in charge of writing them and giving
them a reasonable behaviour.
Some of DTML's features are being ported to Cheetah, such as
Cheetah.Tools.MondoReport
, which is based on the
<dtml-in>
tag. We are also planning an output filter as flexible as
the <dtml-var>
formatting options. However, neither of these are
complete yet.
For a basic introduction to Zope Page Templates, please visit http://www.zope.org/Documentation/Articles/ZPT2.
PHP (http://www.php.net/) is one of the few scripting languages
expressly designed for web servlets. However, it's also a full-fledged
programming language with libraries similar to Python's and Perl's. The
syntax and functions are like a cross between Perl and C plus some original
ideas (e.g.; a single array type serves as both a list and a dictionary,
$arr[]="value";
appends to an array).
Smarty (http://smarty.php.net/) is an advanced template engine for PHP. (Note: this comparision is based on Smarty's on-line documentation. The author has not used Smarty. Please send corrections or ommissions to the Cheetah mailing list.) Like Cheetah, Smarty:
Features Smarty has that Cheetah lacks:
-
as the input file name and --stdout
to send the result to
standard output. Note that Cheetah uses the term ``output filter'' differently
than Smarty: Cheetah output filters (#filter
) operate on placeholders,
while Smarty output filters operate on the entire template output. There has
been a proposed #sed
directive that would operate on the entire output
line by line, but it has not been implemented.
.strip
, .capitalize
, .replace(SEARCH, REPL)
),
but in other cases you must wrap the result in a function call or write
a custom output filter (#filter
).
#extends
. Part of this is
because Cheetah distinguishes between functions and directives, while
Smarty treats them all as ``functions''. Cheetah's design does not
allow functions to have flow control effect outside the function
(e.g., #if
and #for
, which operate on template body lines),
so directives like these cannot be encoded as functions.
Cheetah.SettingsManager
module can parse such a file, but you'd
have to invoke it manually. (See the docstrings in the module for
details.) In Smarty, this feature is used for
multilingual applications. In Cheetah, the developers maintain that everybody
has their own preferred way to do this (such as using Python's gettext
module), and it's not worth blessing one particular strategy in Cheetah since
it's easy enough to integrate third-party code around the template, or to add
the resulting values to the searchList.
Features Cheetah has that Smarty lacks:
Comparisions of various Smarty constructs:
{assign var="name" value="Bob"} (#set has better syntax in the author's opinion) counter (looks like equivalent to #for) eval (same as #include with variable) fetch: insert file content into output (#include raw) fetch: insert URL content into output (no euqivalent, user can write function calling urllib, call as $fetchURL('URL') ) fetch: read file into variable (no equivalent, user can write function based on the 'open/file' builtin, or on .getFileContents() in Template.) fetch: read URL content into variable (no equivalent, use above function and call as: #set $var = $fetchURL('URL') html_options: output an HTML option list (no equivalent, user can write custom function. Maybe FunFormKit can help.) html_select_date: output three dropdown controls to specify a date (no equivalent, user can write custom function) html_select_time: output four dropdown controls to specify a time (no equvalent, user can write custom function) math: eval calculation and output result (same as #echo) math: eval calculation and assign to variable (same as #set) popup_init: library for popup windows (no equivalent, user can write custom method outputting Javascript) Other commands: capture (no equivalent, collects output into variable. A Python program would create a StringIO instance, set sys.stdout to it temporarily, print the output, set sys.stdout back, then use .getvalue() to get the result.) config_load (roughly analagous to #settings, which was removed from Cheetah. Use Cheetah.SettingsManager manually or write a custom function.) include (same as #include, but can include into variable. Variables are apparently shared between parent and child.) include_php: include a PHP script (e.g., functions) (use #extends or #import instead) insert (same as #include not in a #cache region) {ldelim}{rdelim} (escape literal $ and # with a backslash, use #compiler-settings to change the delimeters) literal (#raw) php (``<% %>'' tags) section (#for $i in $range(...) ) foreach (#for) strip (like the #sed tag which was never implemented. Strips leading/trailing whitespace from lines, joins several lines together.) Variable modifiers: capitalize ( $STRING.capitalize() ) count_characters ( $len(STRING) ) count_paragraphs/sentances/words (no equivalent, user can write function) date_format (use 'time' module or download Egenix's mx.DateTime) default ($getVar('varName', 'default value') ) escape: html encode ($cgi.escape(VALUE) ) escape: url encode ($urllib.quote_plus(VALUE) ) escape: hex encode (no equivalent? user can write function) escape: hex entity encode (no equivalent? user can write function) indent: indent all lines of a var's output (may be part of future #indent directive) lower ($STRING.lower() ) regex_replace ('re' module) replace ($STRING.replace(OLD, NEW, MAXSPLIT) ) spacify (#echo "SEPARATOR".join(SEQUENCE) ) string_format (#echo "%.2f" % FLOAT , etc.) strip_tags (no equivalent, user can write function to strip HTML tags, or customize the WebSafe filter) truncate (no equivalent, user can write function) upper ($STRING.upper() ) wordwrap ('writer' module, or a new module coming in Python 2.3)
Some of these modifiers could be added to the super output filter we want to write someday.
PHPLib ((http://phplib.netuse.de/) is a collection of classes for various
web objects (authentication, shopping cart, sessions, etc), but what we're
interested in is the Template
object. It's much more primitive than
Smarty, and was based on an old Perl template class. In fact, one of the
precursors to Cheetah was based on it too. Differences from Cheetah:
{placeholders}
in braces.
set_var
method. However, you can pass
this method an array (dictionary) of several variables at once.
<!-- BEGIN blockName --> ...
<!-- END blockName>
. The set_block
method extracts this text
into a namespace variable and puts a placeholder referring to it in the
template. This has a few parallels with Cheetah's #block
directive but is overall quite different.
#if
, extract the block. Then if true, do
nothing. If false, assign the empty string to the namespace variable.
#for
, extract the block. Set any
namespace variables needed inside the loop. To parse one iteration, use
the parse
method to fill the block variable (a mini-template) into
another namespace variable, appending to it. Refresh the namespace
variables needed inside the loop and parse again; repeat for each
iteration. You'll end up with a mini-result that will be plugged into the
main template's placeholder.
set_file
method. This places the file's content in a namespace variable.
To read a template definition from a string, assign it to a namespace
variable.
Here's a basic Cheetah example:
<TABLE> #for $client in $service.clients <TR> <TD>$client.surname, $client.firstname</TD> <TD><A HREF="mailto:$client.email" >$client.email</A></TD> </TR> #end for </TABLE>
Compare this with PSP:
<TABLE> <% for client in service.clients(): %> <TR> <TD><%=client.surname()%>, <%=client.firstname()%></TD> <TD><A HREF="mailto:<%=client.email()%>"><%=client.email()%></A></TD> </TR> <%end%> </TABLE>
The optik package (Cheetah.Utils.optik) is based on Optik 1.3,
http://optik.sourceforge.net/, ©2001 Gregory P Ward
gward@python.net. It's unmodified from the original version except
the import
statements, which have been adjusted to make them work in
this location. The following license applies to optik:
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This document was generated using the LaTeX2HTML translator.
LaTeX2HTML is Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds, and Copyright © 1997, 1998, Ross Moore, Mathematics Department, Macquarie University, Sydney.
The application of LaTeX2HTML to the Python documentation has been heavily tailored by Fred L. Drake, Jr. Original navigation icons were contributed by Christopher Petrilli.