.py Template Modules — Cheetah3 - The Python-Powered Template Engine

# .py Template Modules

This chapter examines the structure of a .py template module. The following few chapters will then show how each placeholder and directive affects the generated Python code.

## An example

Our first template follows a long noble tradition in computer tutorials. It produces a familiar, friendly greeting. Here’s the template:

    Hello, world!

… the output:

    Hello, world!

… and the .py template module cheetah-compile produced, with line numbers added:

     1 #!/usr/bin/env python

     2 """
     3 Autogenerated by CHEETAH: The Python-Powered Template Engine
     4  CHEETAH VERSION: 0.9.12
     5  Generation time: Sat Apr 20 14:27:47 2002
     6    Source file: x.tmpl
     7    Source file last modified: Wed Apr 17 22:10:59 2002
     8 """

     9 __CHEETAH_genTime__ = 'Sat Apr 20 14:27:47 2002'
    10 __CHEETAH_src__ = 'x.tmpl'
    11 __CHEETAH_version__ = '0.9.12'

    12 ##################################################
    13 ## DEPENDENCIES

    14 import sys
    15 import os
    16 import os.path
    17 from os.path import getmtime, exists
    18 import time
    19 import types
    20 from Cheetah.Template import Template
    21 from Cheetah.DummyTransaction import DummyTransaction
    22 from Cheetah.NameMapper import NotFound, valueForName,
              valueFromSearchList
    23 import Cheetah.Filters as Filters
    24 import Cheetah.ErrorCatchers as ErrorCatchers

    25 ##################################################
    26 ## MODULE CONSTANTS

    27 try:
    28     True, False
    29 except NameError:
    30     True, False = (1==1), (1==0)

    31 ##################################################
    32 ## CLASSES

    33 class x(Template):
    34     """
    35
    36     Autogenerated by CHEETAH: The Python-Powered Template Engine
    37     """

    38     ##################################################
    39     ## GENERATED METHODS

    40     def __init__(self, *args, **KWs):
    41         """
    42
    43         """

    44         Template.__init__(self, *args, **KWs)
    45         self._filePath = 'x.tmpl'
    46         self._fileMtime = 1019106659

    47     def respond(self,
    48             trans=None,
    49             dummyTrans=False,
    50             VFS=valueFromSearchList,
    51             VFN=valueForName,
    52             getmtime=getmtime,
    53             currentTime=time.time):

    54         """
    55         This is the main method generated by Cheetah
    56         """

    57         if not trans:
    58             trans = DummyTransaction()
    59             dummyTrans = True
    60         write = trans.response().write
    61         SL = self._searchList
    62         filter = self._currentFilter
    63         globalSetVars = self._globalSetVars
    64
    65         ########################################
    66         ## START - generated method body
    67
    68         if exists(self._filePath) and getmtime(self._filePath) > \
                       self._fileMtime:
    69             self.compile(file=self._filePath)
    70             write(getattr(self, self._mainCheetahMethod_for_x)
                           (trans=trans))
    71             if dummyTrans:
    72                 return trans.response().getvalue()
    73             else:
    74                 return ""
    75         write('Hello, world!\n')
    76
    77         ########################################
    78         ## END - generated method body
    79
    80         if dummyTrans:
    81             return trans.response().getvalue()
    82         else:
    83             return ""

    84
    85     ##################################################
    86     ## GENERATED ATTRIBUTES

    87     __str__ = respond

    88     _mainCheetahMethod_for_x= 'respond'

    89 # CHEETAH was developed by Tavis Rudd, Chuck Esterbrook, Ian Bicking
           #     and Mike Orr;
    90 # with code, advice and input from many other volunteers.
    91 # For more information visit https://cheetahtemplate.org/

    92 ##################################################
    93 ## if run from command line:
    94 if __name__ == '__main__':
    95     x().runAsMainProgram()

(I added the line numbers for this Guide, and split a few lines to fit the page width. The continuation lines don’t have line numbers, and I added indentation, backslashes and ‘#’ as necessary to make the result a valid Python program.)

The examples were generated from CVS versions of Cheetah between 0.9.12 and 0.9.14.

## A walk through the example

Lines 20-24 are the Cheetah-specific imports. Line 33 introduces our generated class, {x}, a subclass of {Template}. It’s called x because the source file was x.tmpl.

Lines 40-46 are the {.__init__} method called when the template is instantiated or used as a Webware servlet, or when the module is run as a standalone program. We can see it calling its superclass constructor and setting {._filePath} and {._fileMtime} to the filename and modification time (in Unix ticks) of the source .tmpl file.

Lines 47-84 are the main method {.respond}, the one that fills the template. Normally you call it without arguments, but Webware calls it with a Webware {Transaction} object representing the current request. Lines 57-59 set up the {trans} variable. If a real or dummy transaction is passed in, the method uses it. Otherwise (if the {trans} argument is {None}), the method creates a {DummyTransaction} instance. {dummyTrans} is a flag that just tells whether a dummy transaction is in effect; it’ll be used at the end of the method.

The other four {.respond} arguments aren’t anything you’d ever want to pass in; they exist solely to speed up access to these frequently-used global functions. This is a standard Python trick described in question 4.7 of the Python FAQ (http://www.python.org/cgi-bin/faqw.py). {VFS} and {VFN} are the functions that give your template the benefits of NameMapper lookup, such as the ability to use the searchList.

Line 60 initializes the {write} variable. This important variable is discussed below.

Lines 60-63 initialize a few more local variables. {SL} is the searchList. {filter} is the current output filter. {globalSetVars} are the variables that have been defined with {#set global}.

The comments at lines 65 and 78 delimit the start and end of the code that varies with each template. The code outside this region is identical in all template modules. That’s not quite true - {#import} for instance generates additional {import} statements at the top of the module - but it’s true enough for the most part.

Lines 68-74 exist only if the template source was a named file rather than a string or file object. The stanza recompiles the template if the source file has changed. Lines 70-74 seem to be redundant with 75-83: both fill the template and send the output. The reason the first set of lines exists is because the second set may become invalid when the template is recompiled. (This is for { re} compilation only. The initial compilation happened in the {.__init__} method if the template wasn’t precompiled.)

Line 75 is the most interesting line in this module. It’s a direct translation of what we put in the template definition, “Hello, world!” Here the content is a single string literal. {write} looks like an ordinary function call, but remember that line 60 made it an alias to {trans.response().write}, a method in the transaction. The next few chapters describe how the different placeholders and directives influence this portion of the generated class.

Lines 80-83 finish the template filling. If {trans} is a real Webware transaction, {write} has already sent the output to Webware for handling, so we return {“”}. If {trans} is a dummy transaction, {write} has been accumulating the output in a Python {StringIO} object rather than sending it anywhere, so we have to return it.

Line 83 is the end of the {.respond} method.

Line 87 makes code{.__str__} an alias for the main method, so that you can {print} it or apply {str} to it and it will fill the template. Line 88 gives the name of the main method, because sometimes it’s not {.respond}.

Lines 94-95 allow the module to be run directly as a script. Essentially, they process the command-line arguments and them make the template fill itself.