using evoque with pylons

Pylons encourages a good separation between the model, the controllers, and the views. It also is very flexible about using different template engines for different views. This note discusses a way for how to set and use Evoque Templating as the default template engine in a Pylons (minimum version 0.9.7) application.

Let's assume we create a site from scratch, let's call it evoque_site. When asked, enter the template_engine as follows:

$ paster create --template=pylons evoque_site Selected and implied templates: Pylons#pylons Pylons application template Variables: egg: evoque_site package: evoque_site project: evoque_site Enter template_engine (mako/genshi/jinja/etc: Template language) ['mako']: evoque Enter sqlalchemy (True/False: Include SQLAlchemy 0.4 configuration) [False]:

adjust application files

We will then need to add the following codes to the files/functions indicated:

evoque_site.config.environment.load_environment(global_conf, app_conf)

# Evoque Templating: # http://evoque.gizmojo.org/ext/pylons/ # http://evoque.gizmojo.org/usage/api/ import logging from evoque.domain import Domain evoque_domain = Domain( # root folder for the default template collection, must be abspath; # as default use pylon's first templates folder os.path.join(root, app_conf.get("evoque.default_dir") or paths['templates'][0]), # whether evaluation namespace is restricted or not restricted = app_conf.get("evoque.restricted")=="true", # how should any evaluation errors be rendered # int 0 to 4, for: [silent, zero, name, render, raise] errors = int(app_conf.get("evoque.errors", 3)), # evoque logger; additional setings should be specified via the pylons # config ini file, just as for any other logger in a pylons application log = logging.getLogger("evoque"), # [collections] int, max loaded templates in a collection cache_size = int(app_conf.get("evoque.cache_size", 0)), # [collections] int, min seconds to wait between checks for # whether a template needs reloading auto_reload = int(app_conf.get("evoque.auto_reload", 60)), # [collections] bool, consume all whitespace trailing a directive slurpy_directives = app_conf.get("evoque.slurpy_directives")=="true", # [collections/templates] str or class, to specify the *escaped* # string class that should be used i.e. if any str input is not of # this type, then cast it to this type). # Builtin str key values are: "xml" -> qpy.h8, "str" -> unicode quoting = app_conf.get("evoque.quoting", "xml"), # [collections/templates] str, preferred encoding to be tried # first when decoding template source. Evoque decodes templates # strings heuristically, i.e. guesses the input encoding. input_encoding = app_conf.get("evoque.input_encoding", "utf-8"), # [collections/templates] list of filter functions, each having # the following signature: filter_func(s:basestring) -> basestring # The functions will be called, in a left-to-right order, after # template is rendered. NOTE: not settable from the conf ini. filters=[] ) # default template (optional) i.e. what to receive # when calling domain.get_template() with no params if app_conf.get("evoque.default_template"): evoque_domain.get_collection().get_template("", src=app_conf.get("evoque.default_template")) # attach evoque domain to app_globals config['pylons.app_globals'].evoque_domain = evoque_domain

development.ini

The above config load_environment() code may be customized on a per-deployment basis, by specifying any of the following parameters under the [app:main] section of the the deployment's .ini file:

# Evoque Domain : http://evoque.gizmojo.org/ext/pylons/ evoque.default_dir = evoque.default_template = evoque.restricted = false evoque.errors = 3 evoque.cache_size = 0 evoque.auto_reload = 2 evoque.slurpy_directives = true evoque.quoting = xml evoque.input_encoding = utf-8

If evoque.default_dir is not set, then Pylon's first templates folder is used.

The filters parameter (on Domain it only serves as site-wide default) is not settable in the ini. For a representative usage example of filters see the Sub-templates in markdown howto.

logging.getLogger("evoque")

Just like any other logger used in a Pylons application, the evoque logger may be adjusted via a deployment's conf ini file.

evoque_site/lib/base.py

from pylons.templating import pylons_globals, cached_template def render_evoque(template_name, extra_vars=None, cache_key=None, cache_type=None, cache_expire=None, collection=None, raw=False, quoting=None): """ Render a template with Evoque : http://evoque.gizmojo.org/ext/pylons/ Accepts the cache options ``cache_key``, ``cache_type``, and ``cache_expire``. The remaining options affect how template is located, loaded and rendered: - template_name: normally this is the collection-root-relative locator for the template; if template had been previously with location specified via the src option, then may be any arbitrary string identifier. - collection: either(None, str, Collection), an existing collection, None implies the default collection - raw: bool, render the raw template source - quoting: either(str, type), sets the quoted-string class to use, None uses the collection's default, "xml" uses qpy.h8, "str" uses unicode """ # Create a render callable for the cache function def render_template(): # Get the globals # Note: when running in restricted mode which of these globals are # to be exposed should be a lot more selective. pg = pylons_globals() # Update any extra vars if needed if extra_vars: pg.update(extra_vars) # Grab a template reference template = pg['app_globals'].evoque_domain.get_template( template_name, collection=collection, raw=raw, quoting=quoting) return template.evoque(pg, raw=raw, quoting=quoting) return cached_template(template_name, render_template, cache_key=cache_key, cache_type=cache_type, cache_expire=cache_expire) render = render_evoque

evoque_site/setup.py

install_requires=[ "Pylons>=0.9.7", ..., "evoque>=0.3" ]

add a controller and template

Let's first add and edit a simple controller and then add a template just to test:

$ paster controller hello

evoque_site/controllers/hello.py

class HelloController(BaseController): def index(self): # Return a rendered template with evoque c.title = "Hello from evoque!" return render("template.html")

evoque_site/templates/template.html

<html> <head><title>evoque + pylons : ${c.title}</title></head> <style type="text/css"> div.code { white-space: pre; font-family: monospace; line-height: 1.1em; padding: 0.6em; margin-bottom: 2em; border: 1px solid #ccc; background-color: #fafafe; } </style> <body> <h2>${c.title}</h2> <h3>template evaluation context</h3> ${inspect()} #[ outputs a <div class="code"/> ]# </body> </html>

Define a route for the hello.index() view, and load it in your web browser. You should see a simple page that dumps the template evaluation context.