qp

Integrating Evoque Templating with the
QP Web Framework
is pretty straightforward. As an explanation, here’s the echo
demo site, included in the QP distribution, modified to use Evoque.
The changes are probably self-explanatory, but for the record
here’s a commentary on each one:

  • First of all slash.qpy is renamed to slash.py
    as the source code is now 100% python.
  • We import (first 2 import lines) what we need to be able to
    set up an Evoque domain.
  • The functions qp.pub.common.header and
    qp.pub.common.footer
    are no longer needed, so are not imported.
    Instead, we do import qp.pub.common.page, and the template used
    for each page rendering will take care of its own header and footer.
  • We override Publisher.__init__() to be able to
    set up an Evoque domain for the site, via the
    separately specified set_domain() method.

    • We designate the evoque/ sub-folder
      as root for our default template collection,
      but this can be anywhere on the file system.
      We may of course also specify other collections.
    • We extend the evaluation global namespace as we need to,
      here we only will need the pformat utility.
    • We set a template under a name that we will use as default.
  • We override Publisher.page() so that it knows how
    to get and evoque a template. Note that the page() API
    remains identical — except for the added optional template
    keyword by which an export may select which template to use.
    If no template keyword is specified on
    page() then the default template name is used.
  • We migrate the presentation code from SiteDirectory.index()
    to the items.html template. We also tell the
    index() method to use the items.html
    template.
  • Just for the heck of it, we also make items.html
    an overlay,
    overriding only the content sub-template,
    on top of base.html
    that takes over the functionality of
    the header() and footer() QP functions
    while also offering additional flexibility, e.g. may have as many
    base templates as desired, or a base template can be more complex
    than just to handle a header and a footer.

The code – slash.py

import sys
from os.path import join, dirname, abspath
import logging
from evoque.domain import Domain

from qp.pub.publish import Publisher
from qp.pub.common import get_request, page
from qp.fill.directory import Directory
from pprint import pformat

class SitePublisher(Publisher):

    configuration = dict(
        http_address=('', 8001),
        as_https_address=('localhost', 9001),
        https_address=('localhost', 10001),
        scgi_address=('localhost', 11001),
    )
    
    def __init__(self, **kwargs):
        super(SitePublisher, self).__init__(**kwargs)
        self.set_domain()
    
    def set_domain(self):
        default_dir = abspath(join(dirname(__file__), 'evoque'))
        # create template domain instance 
        # here restating all defaults, for doc convenience
        self.domain = Domain(default_dir, 
            restricted=False, errors=3, log=logging.getLogger("evoque"),
            cache_size=0, auto_reload=60, slurpy_directives=True, 
            quoting="xml", input_encoding="utf-8", filters=[]
        )
        # extensions to global namespace
        self.domain.set_on_globals("pformat", pformat)
        # preload a default template, e.g. for error pages
        self.domain.get_collection().get_template("", "base.html")
        # other setup e.g. adding other collections, template aliases
        # see: http://evoque.gizmojo.org/usage/
        
    def page(self, title, *content, **kwargs):
        """(title, *content, **kwargs) -> qpy.xml
        Return a page formatted according to the site-standard.
        """
        # we make use of only the "template" kwarg -- there are 
        # other possibilities, see: domain.get_template()
        template = kwargs.get("template", "")
        return self.domain.get_template(template).evoque(
                        title=title, content=content, **kwargs)
        
class SiteDirectory(Directory):
    """
    This site displays the http request.
    """
    
    def get_exports(self):
        yield '', 'index', None, None
    
    def index(self):
        items = get_request().__dict__.items()
        items.sort()
        return page('HTTP Request', template="items.html", items=items)
    
    def _q_traverse(self, components):
        return self.index()

The templates

base.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>${title}</title>
</head>
<body class="standard">
$begin{content} ${content} $end{content}
$evoque{#content}
</body>
</html>

items.html

$overlay{base.html}
$begin{content}
<h1>${title}</h1>
<div style="margin:1em; padding:1em; border:1px solid gray;">
<dl>
  $for{ key, value in items }
    <dt>${key}</dt>
    <dd style="white-space:pre">${pformat(value)}</dd>
  $rof
</dl>
</div>
$end{content}