wt module

Synopsis

The wt module provides an object-oriented HTML templating system. The design goals of the system were that it should be very simple, that it should involve very low overhead in terms of code repeated per page, that it should achieve as completely as possible the separation of code and data, and that it should promote modular code re-use.

Sub-modules

The wt package contains the following sub-modules:

Usage

The wt system expects you to supply two files for each page that is to be served - an HTML file and a code file. The conventional layout for this is to have a directory named wt in the root of your web tree, the directory structure inside which mirrors the structure of the web site outside the wt directory. For each file in the web site, the corresponding code file is under the wt hierarchy, with the same name but with .py appended. e.g. if you have an HTML file named sales/index.html, its code file would be named wt/sales/index.html.py.

The web server must be configured to pass requests through the wt.Handler request handler. Instructions on how to do this with Apache are included on the wt examples page.

Templates

Template files contain only two constructs of interest to the wt system - replacements, and sections. Replacements are used where generated output should be inserted, and sections are used to divide the template into logical blocks. Each replacement corresponds to a method in a class in the code file, and each section corresponds to a nested class.

Replacements

Replacements consist of two dollar signs followed by an identifier name (which may contain alphanumerics and underscore) and another two dollar signs - for example, $$title$$. You then supply a variable or method of the same name in the current section class, the value or return value of which will be output instead of the literal text of the replacement. Names beinning with an underscore are reserved.

By default, the value will be passed through cgi.html_encode before being output. Doing this by default simplifies programming since it is almost always the correct option. It also means that your code is secure by default against cross-site scripting attacks. (You must also make sure that the browser knows what character set you are using, but since cgi.Request.__init__ automatically specifies the character set for you in the Content-Type header, you are secure by default here as well.)

To use another encoding, you can put an encoding specifier character before the identifier name. The two alternative encodings are % for cgi.url_encode (e.g. $$%page$$) and = to output the return value unchanged (e.g. $$=html$$). Care must be taken with the literal encoding to ensure that no unverified user input ends up being sent to the client's browser.

Example:

<a href="article.html?id=$$%id$$">$$title$$</a>

class main(wt.TemplateCode):
  def id(self): return 123
  def title(self): return "this is the title"

Sections

Sections begin with an HTML comment containing only wt: and an identifier name (which may contain alphanumerics and underscore) - for example, <!--wt:newsitem-->. The section is ended by a similar comment but with a / before the identifier name - for example, <!--wt:/newsitem-->. All the data between the start and end markers is the content of the section. Sections can be nested, but you cannot nest a section inside another with the same name. Names beginning with an underscore are reserved.

The code corresponding to a section is a class subclassed from wt.TemplateCode. An instance of the class will be created and the section content passed to the TemplateCode.main. This new instance will be used to look for methods to satisfy replacements.

If you do not need the section to have any content, a combined start-and-end marker in the same comment is achievable by placing a / character after the identifier name - e.g., <!--wt:_page/-->. This is useful, for example, with wt.GlobalTemplate sections.

Please note that the start and end markers must appear exactly as described - no white space is allowed at any point inside the marker. <! --wt:invalid--> is not valid, for example.

For example:

<!--wt:newsitem-->
<a href="article.html?id=$$%id$$">$$title$$</a>
<!--wt:/newsitem-->

class main(wt.TemplateCode):
  class newsitem(wt.TemplateCode):
    def id(self): return 123
    def title(self): return "this is the title"

class: TemplateCode

The base class for all code corresponding to template sections.

Public Instance Variables

wt

A reference to the wt.Handler instance which is handling this request.

req

A reference to the cgi.Request instance which contains information about this request.

outer

A reference to the TemplateCode instance which corresponds to the next outer-most section in the template - i.e. an instance of the class that this class is nested within. This is not the same thing as super, which is the class this class is derived from. If there is no enclosing class then outer is None.

Public Methods

process(self, template, selected=None)

template: string
selected: None, or a string, or a sequence of strings

This method is called to process a template string. The template parameter contents the template to be processed. Variables and methods to satisfy replacements and classes to satisfy sections are looked for inside self.

If selected is None then all top-level sections in the template string are executed. If it is a string or sequence of strings then only top-level sections with a name matching that string or in that sequence will be executed, and sections with other names will be ignored and no output produced for them.

Template sections with the special name _null are ignored. The content of these sections is always discarded, regardless of the value of the selected parameter, and therefore no corresponding class is required in the code file.

main(self, template)

template: string

This method may be overridden by subclasses. The default implementation simply passes the template parameter, which is the contents of the section which caused this object to be created, to the process method.

A lot of the power of the templating system is provided by overriding this method. By redefining it you can cause the template section to be output multiple times, or not at all, or indeed ignore the process method altogether and do something entirely different with the template parameter. You can send output directly using the write method of the self.req variable.

Examples of the use of TemplateCode are given in the wt examples page.

class: GlobalTemplate(TemplateCode)

A base class for template sections where the template is to be fetched from another source rather than be found in-line in the HTML file. The normal HTML contents of any section derived from GlobalTemplate are temporarily suspended and used for a subsection named page instead. A separate file is read to provide the HTML template for the GlobalTemplate section.

Examples of the use of GlobalTemplate are given in the wt examples page.

Public Class Variables

page

This variable may be overridden by subclasses. A TemplateCode subclass which is called with the original template contents that would otherwise have been used for the GlobalTemplate class. The default value is TemplateCode. Due to the extra processing which GlobalTemplate interposes, the corresponding HTML template section to this class should be named _page, not page.

Public Methods

template_name(self)

Returns: a string

This method may be overridden by subclasses. This method returns the filename to read to fetch the template contents for this section. The default implementation returns self.wt.etc + "/template.html".

class: Handler(cgi.Handler)

This Handler class should be called to process a request using the wt templating system. The default implementation uses various environment variables which will have been set up by the Apache configuration shown on the wt examples page to determine the code and template names, but various methods are provided which may be overridden to make these choices in a different way (for example, if you are using a different web server). All wt.TemplateCode objects receive a reference to the current instance in their self.wt instance variable.

Public Instance Variables

req

A reference to the cgi.Request instance which contains information about this request.

etc

The directory DOCUMENT_ROOT + "../etc". This is used as a default location by GlobalTemplate.template_name to locate templates. It is also a useful location to place miscellaneous files associated with a web site that should not be under the DOCUMENT_ROOT.

template

The full pathname of the template file.

Public Methods

get_template_encoding(self)

This method may be overridden by subclasses. It returns the character encoding used for the template file, or None if no encoding conversion is to be done. If it is not None then the template file will be assumed to be using the specified character encoding and the template parameter to TemplateCode.main will be a unicode string instead of a normal string. The default implementation returns None.

pre_load(self)

This method may be overridden by subclasses. Its default implementation does nothing. It is called before the template is located or the page code loaded. self.req and self.etc are available.

pre_request(self, obj)

obj: wt.TemplateCode instance

This method may be overridden by subclasses. Its default implementation does nothing. It is called just before obj.main() is called to process the request. All the instance variables of self have already been set up.

post_request(self, obj)

obj: wt.TemplateCode instance

This method may be overridden by subclasses. Its default implementation does nothing. It is called just after obj.main() has handled the request.

process(self, req)

req: cgi.Request instance

This method may be overridden by subclasses. It calls self._get_template(), self._get_code() and self._get_etc() to determine the various files and directories to use when handling the request. The code file should contain a subclass of wt.TemplateCode named main, which is passed the entire template file. The global namespace the code file is executed in is initialised to contain a reference to the wt module in the variable wt, thus avoiding the need to do import jon.wt as wt in every code file. See the wt examples page for how to set up Apache so that wt knows what's going on.

You can add code to run before and/or after every request by overriding this method and performing processing before and/or after calling the base wt.Handler.process base method.

Example:

class Handler(wt.Handler):
  def process(self, req):
    self.session = session.Session(req, url=0)
    wt.Handler.process(self, req)
    self.session.save()
fcgi.Request({fcgi.FCGI_RESPONDER: Handler}).run()

Protected Methods

_get_template(self)

Returns: string

This method may be overridden by subclasses. It returns the full pathname of the template file to be used for this request. self.req has already been set up. The default implementation looks for an environment variable whose name matches (REDIRECT_){0,4}WT_TEMPLATE_FILENAME.

_get_code(self)

Returns: string

This method may be overridden by subclasses. It returns the full pathname of the code file to be used for this request. self.req and self.template have already been set up. The default implementation returns the environment variable PATH_TRANSLATED.

_get_etc(self)

Returns: string

This method may be overridden by subclasses. It returns the full pathname of the directory which self.etc will be set to. self.req has already been set up. The pathname should not end with a / character. The default implementation returns the equivalent of DOCUMENT_ROOT/../etc.

class: DebugHandler(cgi.DebugHandlerMixIn, Handler)

This class is identical to Handler, except that it uses cgi.DebugHandlerMixIn so that if an exception is thrown by a template page then a traceback will be sent to the browser. This class may be used during development to aid debugging but should never be used in a production environment since it will leak private information to the browser.

$Id: wt.html,v c0f5f983a7fc 2010/03/23 01:07:17 jon $