Genshi Recipes: Using Genshi with Pylons
In Pylons 0.9.6rc1, you need to replace template_engine='mako' with template_engine='genshi' in config/environment.py.
Apparently as of Pylons 0.9.5, if you have Genshi installed you may invoke Genshi templates just by using render_response("genshi","<templatename>"). The instructions below are helpful for making genshi the "default" templates.
To use Genshi with Pylons 0.9.4 and below, you need to take some additional steps, which is what's going to be explained here. See also the Pylons Cookbook variant
Adding Genshi Template Engine
First you need some changes in your application's middleware.py.
Genshi only
# Load our Pylons configuration defaults config = load_environment() config.init_app(global_conf, app_conf, package='<appname>') # Setup Genshi(only) Template Engine config.template_engines = [] config.add_template_engine('genshi', '<appname>.templates', {})
Genshi and Myghty
# Load our Pylons configuration defaults config = load_environment() config.init_app(global_conf, app_conf, package='<appname>') # Setup Genshi Template Engine myghty = config.template_engines.pop() config.add_template_engine('genshi', '<appname>.templates', {}) config.template_engines.append(myghty)
Finally, the Pylons template plug-ins currently expect paths to act as module imports, so you will also need to create an empty __init__.py file inside appname/templates.
WebHelpers and Genshi
To use WebHelpers within a Genshi template, the helper return values need to be wrapped in a Markup object, as it would otherwise be escaped. Think carefully before following this suggestion, however, as this effectively works around the white-listing effect of the Markup object, automatically running any HTML that users may submit to your site. It is safer (albiet much more annoying) to manually wrap specific WebHelpers? in your pages.
The Hard Way
You can do for example(I won't explain the template, for that consult the Genshi Guide):
<!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" xmlns:py="http://genshi.edgewall.org/" xmlns:xi="http://www.w3.org/2001/XInclude" py:strip=""> <head py:match="head"> <title>The Title</title> </head> <body> <h1>hello</h1> ${XML(h.<helper>)} </body> </html>
...but the above becomes quite painfull when using several WebHelpers.
The Easy Way
The solution is to wrap all helper functions into Markup objects. For that, edit <appname>/lib/helpers.py and add:
from genshi.core import Markup def wrap_helpers(localdict): def helper_wrapper(func): def wrapped_helper(*args, **kw): if not callable(func(*args, **kw)): return Markup(func(*args, **kw)) else: return Markup(func(*args, **kw)()) wrapped_helper.__name__ = func.__name__ return wrapped_helper for name, func in localdict.iteritems(): if not callable(func) or not func.__module__.startswith('webhelpers.rails'): continue localdict[name] = helper_wrapper(func) wrap_helpers(locals())
Note: as of WebHelpers 1.0 the webhelpers.rails package has been removed and it seems the wrap_helpers workaround above isn't required anymore(?)
Now edit <appname>/config/middleware.py and just add:
from <appname>.lib import helpers
The above will cause all helpers to be wrapped uppon application initialization.
Now you can use the WebHelpers like you used to with Myghty, for example:
<!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" xmlns:py="http://genshi.edgewall.org/" xmlns:xi="http://www.w3.org/2001/XInclude" py:strip=""> <head py:match="head"> <title>The Title</title> </head> <body> <h1>hello</h1> ${h.<helper>} </body> </html>
Final Thoughts
You might also think about adding to <appname>/lib/helpers.py:
from genshi.builder import tag
The Genshi tag object is just like the content_tag() WebHelper, but it will be faster since it does not have to pass through the wrapper.
And that's all....