summaryrefslogtreecommitdiff
path: root/www/users_guide/tipsAndTricks.rst
diff options
context:
space:
mode:
Diffstat (limited to 'www/users_guide/tipsAndTricks.rst')
-rw-r--r--www/users_guide/tipsAndTricks.rst586
1 files changed, 586 insertions, 0 deletions
diff --git a/www/users_guide/tipsAndTricks.rst b/www/users_guide/tipsAndTricks.rst
new file mode 100644
index 0000000..4438990
--- /dev/null
+++ b/www/users_guide/tipsAndTricks.rst
@@ -0,0 +1,586 @@
+Tips, Tricks and Troubleshooting
+================================
+
+(tips)
+
+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.
+
+Placeholder Tips
+----------------
+
+(tips.placeholder)
+
+Here's how to do certain important lookups that may not be obvious.
+For each, we show first the Cheetah expression and then the Python
+equivalent, because you can use these either in templates or in
+pure Python subclasses. The Cheetah examples use NameMapper
+shortcuts (uniform dotted notation, autocalling) as much as
+possible.
+
+To verify whether a variable exists in the searchList:
+
+::
+
+ $varExists('theVariable')
+ self.varExists('theVariable')
+
+This is useful in {#if} or {#unless} constructs to avoid a
+{#NameMapper.NotFound} error if the variable doesn't exist. For
+instance, a CGI GET parameter that is normally supplied but in this
+case the user typed the URL by hand and forgot the parameter (or
+didn't know about it). ({.hasVar} is a synonym for {.varExists}.)
+
+To look up a variable in the searchList from a Python method:
+
+::
+
+ self.getVar('theVariable')
+ self.getVar('theVariable', myDefault)
+
+This is the equivalent to {$theVariable} in the template. If the
+variable is missing, it returns the second argument, {myDefault},
+if present, or raises {NameMapper.NotFound} if there is no second
+argument. However, it usually easier to write your method so that
+all needed searchList values come in as method arguments. That way
+the caller can just use a {$placeholder} to specify the argument,
+which is less verbose than you writing a getVar call.
+
+To do a "safe" placeholder lookup that returns a default value if
+the variable is missing:
+
+::
+
+ $getVar('theVariable', None)
+ $getVar('theVariable', $myDefault)
+
+To get an environmental variable, put {os.environ} on the
+searchList as a container. Or read the envvar in Python code and
+set a placeholder variable for it.
+
+Remember that variables found earlier in the searchList override
+same-name variables located in a later searchList object. Be
+careful when adding objects containing other variables besides the
+ones you want (e.g., {os.environ}, CGI parameters). The "other"
+variables may override variables your application depends on,
+leading to hard-to-find bugs. Also, users can inadvertently or
+maliciously set an environmental variable or CGI parameter you
+didn't expect, screwing up your program. To avoid all this, know
+what your namespaces contain, and place the namespaces you have the
+most control over first. For namespaces that could contain
+user-supplied "other" variables, don't put the namespace itself in
+the searchList; instead, copy the needed variables into your own
+"safe" namespace.
+
+Diagnostic Output
+-----------------
+
+(tips.diagnostic)
+
+If you need send yourself some debugging output, you can use
+{#silent} to output it to standard error:
+
+::
+
+ #silent $sys.stderr.write("Incorrigible var is '$incorrigible'.\n")
+ #silent $sys.stderr.write("Is 'unknown' in the searchList? " +
+ $getVar("unknown", "No.") + "\n" )
+
+(Tip contributed by Greg Czajkowski.)
+
+When to use Python methods
+--------------------------
+
+(tips.pythonMethods)
+
+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.
+
+Calling superclass methods, and why you have to
+-----------------------------------------------
+
+(tips.callingSuperclassMethods)
+
+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 ...
+ ===========================================================================
+
+All methods
+-----------
+
+(tips.allMethods)
+
+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 inheritanceEtc.extends) unless you intend to
+override the standard method.
+
+Variables with a star prefix ({ \*}) are frequently used in
+templates or in pure Python classes.
+
+\*{Inherited from Cheetah.Template}
+
+ Compile the template. Automatically called by {.\_\_init\_\_}.
+
+ Return the module code the compiler generated, or {None} if no
+ compilation took place.
+
+ Return the class code the compiler generated, or {None} if no
+ compilation took place.
+
+ Return a reference to the underlying search list. (a list of
+ objects). Use this to print out your searchList for debugging.
+ Modifying the returned list will affect your placeholder searches!
+
+ Return a reference to the current error catcher.
+
+ If 'cacheKey' is not {None}, refresh that item in the cache. If
+ {None}, delete all items in the cache so they will be recalculated
+ the next time they are encountered.
+
+ Break reference cycles before discarding a servlet.
+
+ Look up a variable in the searchList. Same as {$varName} but allows
+ you to specify a default value and control whether autocalling
+ occurs.
+
+ Read the named file. If used as a placeholder, inserts the file's
+ contents in the output without interpretation, like {#include raw}.
+ If used in an expression, returns the file's content (e.g., to
+ assign it to a variable).
+
+ This is what happens if you run a .py template module as a
+ standalone program.
+
+
+\*{Inherited from Cheetah.Utils.WebInputMixin}
+
+ Exception raised by {.webInput}.
+
+ Convenience method to access GET/POST variables from a Webware
+ servlet or CGI script, or Webware cookie or session variables. See
+ section webware.webInput for usage information.
+
+
+\*{Inherited from Cheetah.SettingsManager}
+
+ Get a compiler setting.
+
+ Does this compiler setting exist?
+
+ Set setting 'name' to 'value'. See {#compiler-settings}, section
+ parserInstructions.compiler-settings.
+
+ Return the underlying settings dictionary. (Warning: modifying this
+ dictionary will change Cheetah's behavior.)
+
+ Return a copy of the underlying settings dictionary.
+
+ Return a deep copy of the underlying settings dictionary. See
+ Python's {copy} module.
+
+ Update Cheetah's compiler settings from the 'newSettings'
+ dictionary. If 'merge' is true, update only the names in
+ newSettings and leave the other names alone. (The SettingsManager
+ is smart enough to update nested dictionaries one key at a time
+ rather than overwriting the entire old dictionary.) If 'merge' is
+ false, delete all existing settings so that the new ones are the
+ only settings.
+
+ Same, but pass a string of {name=value} pairs rather than a
+ dictionary, the same as you would provide in a {#compiler-settings}
+ directive, section parserInstructions.compiler-settings.
+
+ Same, but exec a Python source file and use the variables it
+ contains as the new settings. (e.g.,
+ {cheetahVarStartToken = "@"}).
+
+ Same, but get the new settings from a text file in ConfigParser
+ format (similar to Windows' \*.ini file format). See Python's
+ {ConfigParser} module.
+
+ Same, but read the open file object 'inFile' for the new settings.
+
+ Same, but read the new settings from a string in ConfigParser
+ format.
+
+ Write the current compiler settings to a file named 'path' in
+ \*.ini format.
+
+ Return a string containing the current compiler settings in \*.ini
+ format.
+
+
+\*{Inherited from Cheetah.Servlet}
+
+{ 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
+tips.callingSuperclassMethods.)
+
+ True if this template instance is part of a live transaction in a
+ running WebKit servlet.
+
+ True if Webware is installed and the template instance inherits
+ from WebKit.Servlet. If not, it inherits from
+ Cheetah.Servlet.DummyServlet.
+
+ Called by WebKit at the beginning of the web transaction.
+
+ Called by WebKit at the end of the web transaction.
+
+ Called by WebKit to produce the web transaction content. For a
+ template-servlet, this means filling the template.
+
+ Break reference cycles before deleting instance.
+
+ The filesystem pathname of the template-servlet (as opposed to the
+ URL path).
+
+ The current Webware transaction.
+
+ The current Webware application.
+
+ The current Webware response.
+
+ The current Webware request.
+
+ The current Webware session.
+
+ Call this method to insert text in the filled template output.
+
+
+Several other goodies are available to template-servlets under the
+{request} attribute, see section webware.input.
+
+{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.
+
+\*{Inherited from WebKit.Servlet} These are accessible only if
+Cheetah knows Webware is installed. This listing is based on a CVS
+snapshot of Webware dated 22 September 2002, and may not include
+more recent changes.
+
+The same caveats about overriding these methods apply.
+
+ The simple name of the class. Used by Webware's logging and
+ debugging routines.
+
+ Used by Webware's logging and debugging routines.
+
+ True if the servlet can be multithreaded.
+
+ True if the servlet can be used for another transaction after the
+ current transaction is finished.
+
+ Depreciated by {.serverSidePath()}.
+
+
+Optimizing templates
+--------------------
+
+(tips.optimizing)
+
+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
+output.caching).
+
+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)
+
+Otherwise you'd have to call {self.getVar('arg1')} etc in your
+method, which is more wordy, and tedious.
+
+PSP-style tags
+--------------
+
+(tips.PSP)
+
+{<%= ... %>} 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!
+
+you'll get a {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.
+
+Makefiles
+---------
+
+(tips.Makefile)
+
+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.
+
+Using Cheetah in a Multi-Threaded Application
+---------------------------------------------
+
+(tips.threads)
+
+Template classes may be shared freely between threads. However,
+template instances should not be shared unless you either:
+
+
+- Use a lock (mutex) to serialize template fills, to prevent two
+ threads from filling the template at the same time.
+
+- Avoid thread-unsafe features:
+
+
+ - Modifying searchList values or instance variables.
+
+ - Caching ({$\*var}, {#cache}, etc).
+
+ - {#set global}, {#filter}, {#errorCatcher}.
+
+
+ Any changes to these in one thread will be visible in other
+ threads, causing them to give inconsistent output.
+
+
+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.
+
+Using Cheetah with gettext
+--------------------------
+
+(tips.gettext)
+
+{ 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:
+
+
+- xgettext is used on compiled templates, not on the templates
+ themselves.
+
+- The way the NameMapper syntax gets compiled to Python gets in
+ the way of the syntax that xgettext recognizes. Hence, a special
+ case exists for the functions {\_}, {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.
+
+
+