Genshi Templates in Nevow

Posted on March 25, 2007 by oubiwann


Blog post image

Update: When done reading through this example and code, please see the most recent blo g post about this that addresses the dyn amic rendering of Genshi templates in Nevow.

I have been exploring the extensibility of Nevow, and I'm finding it surprisingly easy to integrate other tools. I've only used Genshi for recent Trac hacking, but I hear more and more about it and it seems to be gaining a little momentum as one of the preferred template systems for python web application developers.

Using the code from the blog post Object Publishing with Nevow, I have created an example of how to integrate Genshi with Nevow. I will provide a link to the source code at the end of the post.

Integrating another templating system into Nevow is actually a no-brainer: you just need to have the "alien" template parsed by its own parsers prior to Nevow performing its parsing. This impacts only one module: nevow.loaders.

Before we dig any deeper, how about some eye-candy? Then a quick review, and finally the code. Here are some screenshots of the Genshi templates running along-side native Nevow templates:


434358390 65710Bc3A0 O
434358446 Df7816377A O

The second image is the page in the little demo that showcases all the functionality of Genshi as documented on this page.

Traditionally with Nevow, Page classes contain data_*() and render_*() methods. These Page classes are "web resources" whose locateChild() method is called after an HTTP GET. Each page class that will have an HTML view needs to set a docFactory attribute; this is the loader instance I referred to above.

Here is a toy example of a page class from a previous blog post:

from nevow import rend
from nevow import loaders

class SiteRoot(rend.Page):

docFactory = loaders.xmlstr('''<!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"
xmlns:nevow="http://nevow.com/ns/nevow/0.1">
</html>''')
What we need is to be able to do something link this:
from nevow import rend

import myloaders

class GenshiStuffResource(rend.Page):

docFactory = myloaders.genshistr('''<!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"
xmlns:nevow="http://nevow.com/ns/nevow/0.1"
xmlns:genshi="http://genshi.edgewall.org/">
<h1>Genshi Test</h1>
<div>
<span genshi:with="y=7; x=y**2; z=x+10">$x $y $z</span>
</div>
<div>
<span>Your name is ${username}</span>
</div>
</html>''')
To make this work, all we have to do is create myloaders.py with the following content:

from genshi.template import MarkupTemplate

from nevow import inevow
from nevow.loaders import xmlstr

class genshistr(xmlstr):

def load(self, ctx=None, preprocessors=()):
attrs = inevow.IRenderer(ctx).dict
tmpl = MarkupTemplate(self.template)
xmlStr = tmpl.generate(**attrs).render('xhtml')
self.template = xmlStr
return super(genshistr, self).load(ctx=ctx,
preprocessors=preprocessors)
There is a minimal amount of magic happening here: MarkupTemplate.generate() takes keywords (or a dict, with extended call syntax) and those key/value pairs are available to the template that is rendered. We are using our class's dict for this; so if you want data in your template, you need to make it a class attribute. There are many ways to do this, and you can choose the one that is safest, cleanest, and least consumptive of resources for your application.

This is an example using a string as a template. The source code link below includes a folder where the templates are broken out into files and with a myloaders.genshifile class defined. The screenshots above were taken from a running instance of that example.

Browse the example source code here: nevow/templating/genshi.

Technorati Tags: , , , ,

Author oubiwann
Date March 25, 2007
Time 21:26:08
Category
Tags
Line Count 1
Word Count 666
Character Count 7156

Comments?
This blog doesn't use standard (embedded) comments; however, since the site is hosted on Github, if there is something you'd like to share, please do so by opening a "comment" ticket!