web.py + mako

62 views
Skip to first unread message

Ryan Tracey

unread,
Aug 31, 2007, 9:57:25 AM8/31/07
to we...@googlegroups.com
Hi

What is the correct way to use another templating system from within
web.py. My first attempt results in correctly generated mako output
wrapped in <pre> tags.

How should I be calling the mako template?

--- code.py ---
import web

urls = (
'/(.*)', 'hello'
)

from mako.lookup import TemplateLookup
mylookup = TemplateLookup(directories=['templates/'],
module_directory='mako_modules')

def serve_template(templatename, **kwargs):
mytemplate = mylookup.get_template(templatename)
print mytemplate.render(**kwargs)

class hello:
def GET(self, name):
i = web.input(times=1)
if not name:
name = 'world'
serve_template('hello.html', name=name, times=int(i.times))


if __name__ == "__main__":
web.run(urls, globals())
---

--- templates/hello.html ---
<ol>
% for n in range(times):
<li> ${n} ${name} </li>
% endfor
</ol>
----

Thanks,
Ryan

--
Ryan Tracey
Citizen: The World

lui...@gmail.com

unread,
Aug 31, 2007, 10:24:39 AM8/31/07
to web.py
I'm just curious...
What are the advantages of Mako over Templator or Cheetah, if any?

Anand

unread,
Aug 31, 2007, 10:38:44 AM8/31/07
to we...@googlegroups.com
>
> from mako.lookup import TemplateLookup
> mylookup = TemplateLookup(directories=['templates/'],
> module_directory='mako_modules')
>
> def serve_template(templatename, **kwargs):
> mytemplate = mylookup.get_template(templatename)
> print mytemplate.render(**kwargs)


I think templator approach is the best.

from mako.lookup import TemplateLookup

class mako_render:
def __init__(path):
self._lookup = TemplateLookup(directories=[path],
module_directory='mako_modules')

def __getattr__(self, name):
path = name + '.html'
t = self._lookup.get_template(path)
t.__call__ = t.render
return t

render = mako_render('templates/')

class hello:
def GET(self, name):
i = web.input(times=1)
if not name:
name = 'world'

print render.hello(name=name, times=int(i.times))


Ryan Tracey

unread,
Aug 31, 2007, 11:34:23 AM8/31/07
to we...@googlegroups.com
On 31/08/2007, Anand <anand...@gmail.com> wrote:
>
> > from mako.lookup import TemplateLookup
> > mylookup = TemplateLookup(directories=['templates/'],
> > module_directory='mako_modules')
> >
> > def serve_template(templatename, **kwargs):
> > mytemplate = mylookup.get_template(templatename)
> > print mytemplate.render(**kwargs)
>
>
> I think templator approach is the best.

I have no preferences as yet. Just in the process of converting a
web.py 0.1 app into a web.py 0.2 app and hit some snags with templator
-- probably just my own conditioning that needs to change ;-)

Do you reckon there'll be a performance hit associated with using a
third-party templating system?

> from mako.lookup import TemplateLookup
>
> class mako_render:
> def __init__(path):
> self._lookup = TemplateLookup(directories=[path],
> module_directory='mako_modules')
>
> def __getattr__(self, name):
> path = name + '.html'
> t = self._lookup.get_template(path)
> t.__call__ = t.render
> return t
>
> render = mako_render('templates/')
>
> class hello:
> def GET(self, name):
> i = web.input(times=1)
> if not name:
> name = 'world'
> print render.hello(name=name, times=int(i.times))

Thanks very much Anand, I'll give this a try.

Cheers,

Adam Atlas

unread,
Aug 31, 2007, 11:37:54 AM8/31/07
to we...@googlegroups.com

On 31 Aug 2007, at 11.34, Ryan Tracey wrote:
> Do you reckon there'll be a performance hit associated with using a
> third-party templating system?

Not at all. Templetor isn't really integrated with the rest of web.py
much; using an external one shouldn't make a difference. Actually I
think Mako is faster than the current version of Templetor.

Ryan Tracey

unread,
Aug 31, 2007, 6:41:31 PM8/31/07
to we...@googlegroups.com

Thanks Adam. I think I'll try get my head around both. Horses for
courses and all that.

Ryan Tracey

unread,
Sep 2, 2007, 3:05:44 PM9/2/07
to we...@googlegroups.com

Hi Anand

I tried out the method you suggested but had to make a few changes get
it to work (in my environment?) For instance, despite the "t.__call__
= t.render" in __getattr__ I cannot call render.hello(...). I can, as
expected, call render.hello.__call__(...). I got around this by having
__getattr__ return t.render instead of just t. Also, to get around the
problem of web.py wrapping the template's output in <pre> tags I call
web.header(...) before I call render.hello(...). Here is what I am
doing:

from mako.lookup import TemplateLookup
class mako_render:

def __init__(self, path):


self._lookup = TemplateLookup(directories=[path],
module_directory='mako_modules')
def __getattr__(self, name):
path = name + '.html'
t = self._lookup.get_template(path)

#t.__call__ = t.render
return t.render

render = mako_render('templates/')

class hello:
def GET(self, name):
i = web.input(times=1)
if not name:
name = 'world'

web.header("Content-Type", "text/html; charset=utf-8")
print render.hello(name=name, times=int(i.times))

Can you see any way I could get around having to use the web.header
method? By returning the method (t.render) and not the object (t) am I
necessitating the use of web.header? I dunno, my OO knowledge is very
poor, for instance I was blown away by __gettr__ and had to contrive a
simple case to understand it. Don't laugh:

In [7]: class Foo:
...: def __init__(self, action):
...: self.action = action
...: def __getattr__(self, thing):
...: return thing +' '+ self.action
...:

In [8]: f = Foo('barks')

In [9]: f.dog
Out[9]: 'dog barks'

Thanks again for the suggestion -- I now know a bit more than I did on Friday!

Cheers,
Ryan

Sam

unread,
Oct 13, 2007, 12:59:20 PM10/13/07
to web.py
Hi Ryan,

I've been using mako recently for its feature set and caching
abilities so wanted to integrate it into the new web.py v0.3. This is
what I came up with based on Anands example. It's fairly well tested
against the latest webpy.dev branch.

Add to the bottom of web/template.py (or refactor to your pleasing):
class render_mako:
"""
A web.py-ish interface to the Mako templating engine.

See http://webpy.org/, http://makotemplates.org/
"""
def __init__(self, path='.', ext='.html', compile_path=None,
_lookup=None):
"""
Create a new mako template renderer.

Example:
render = web.template.render_mako('templates/')
render.something(var='value')

Common usage:
web.render = web.template.render_mako('templates/')

Parameters:
path: The directory in which to look for templates. (default:
'.')
ext: Extension to add to template files. (default: '.html')
compile_path: Compile templates to specified directory.
(default: None = no caching)
"""
import mako.template, mako.lookup

# Enable rendering mako template objects by calling
mako.template.Template.__call__ =
mako.template.Template.render

self.path = path
self.ext = ext
if _lookup is None:
_lookup = mako.lookup.TemplateLookup(
directories=[path],
module_directory=compile_path)
self._lookup = _lookup

def __str__(self):
return repr(self)

def __repr__(self):
return '<web.template.render_mako path=\'%(path)s\' ext=\'%
(ext)s\'>' % self.__dict__

def __getattr__(self, name):
"""
Tries to return a template of the given attribute name, or a
new
render object rooted in the attribute named directory, or
throws
a KeyError.
"""
import os.path

template = os.path.join(
self.path[len(self._lookup.directories[0]):],
name + self.ext)
path = os.path.join(self.path, name)
if self._lookup.has_template(template):
return self._lookup.get_template(template)
elif os.path.isdir(path):
return render_mako(path, ext=self.ext,
_lookup=self._lookup)
else:
raise KeyError("Template or directory '%s' does not
exist." % name)


A little example (not thoroughly tested):

hello.py:
import web

web.render = web.template.render_mako(
path='docs/', compile_path='var/cache/templates')

urls = (
'/(.*)?', 'hello',
)

class queue:
def GET(self, name=None):
web.header('Content-Type', 'text/html')
if name != None:
return web.render.hello.name(locals())
else:
return web.render.hello.noname()

def hello_app():
return web.application(urls, globals())


docs/layout.html:
<html><head><title>Hello Example</title></head><body>${next.body()}</
body></html>


docs/hello/name.html:
<%inherit file="/layout.html"/>
Hi ${name}!


docs/hello/noname.html:
<%inherit file="/layout.html"/>
Hello!


I also use a small start-up script to make reloading work:

start.py:
import web
from hello import hello_app

if __name__ == "__main__":
import sys
middleware = []
app = hello_app()
if '--debug' in sys.argv:
sys.argv.remove('--debug')
middleware.append(web.reloader)
app.internalerror = web.debugerror
app.run(*middleware)


using `./start.py --debug` helps.

TODO:
- Maybe using the render_mako method should automatically include the
Content-Type header?
- I can see this turning into a templating API. :-D

Regards,

Samuel Cochran


On Sep 3, 3:05 am, "Ryan Tracey" <ryan.tra...@gmail.com> wrote:
> On 31/08/07, Ryan Tracey <ryan.tra...@gmail.com> wrote:

Anand

unread,
Oct 13, 2007, 9:38:16 PM10/13/07
to we...@googlegroups.com

On 13-Oct-07, at 10:29 PM, Sam wrote:

>
> Hi Ryan,
>
> I've been using mako recently for its feature set and caching
> abilities so wanted to integrate it into the new web.py v0.3. This is
> what I came up with based on Anands example. It's fairly well tested
> against the latest webpy.dev branch.
>
> Add to the bottom of web/template.py (or refactor to your pleasing):

No need to refactor. 0.3 will support interface to various templating
engines.
It have added a version, supporting cheetah, genshi and mako.
If you have any other favorite templating engine, please let me know,
preferably with a patch to support that.

The interface will look very similar to web.py templating system.

Some examples:

render = web.contrib.template.render_mako(directories=
['templates'])
render = web.contrib.template.render_genshi(['templates/'])

Reply all
Reply to author
Forward
0 new messages