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" <[EMAIL PROTECTED]> wrote:
> On 31/08/07, Ryan Tracey <[EMAIL PROTECTED]> wrote:
>
>
>
> > On 31/08/2007, Anand <[EMAIL PROTECTED]> 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.
>
> 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


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"web.py" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/webpy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to