template.py
author Tero Marttila <terom@fixme.fi>
Tue, 10 Feb 2009 01:07:15 +0200
changeset 56 dfb1c755e972
parent 50 e4fbf480fbee
child 70 add1c1f7831c
permissions -rw-r--r--
fix bug with zero values in query args
"""
    Template handler
"""

from mako import exceptions, util
from mako.runtime import Context
from mako.template import Template
import mako.lookup

from qmsk.web import http, helpers

# path to template files
TEMPLATE_DIR = "templates"

# path to cached templates
CACHE_DIR = "cache/templates"

# template file extension
TEMPLATE_EXT = "tmpl"

class TemplateError (http.ResponseError) :
    """
        Raised by the template module functions
    """

    pass

class TemplateLoader (mako.lookup.TemplateLookup) :
    """
        Our own specialization of mako's TemplateLookup
    """

    def __init__ (self, path, fileext=TEMPLATE_EXT, _helper_class=helpers.Helpers, **env) :
        """
            Initialize to load templates located at path, with the given file extension.

            The given Helpers class is used to provide the helper methods

            The given **env list is supplied to every template render
        """

        # store
        self.path = path
        self.fileext = fileext
        self.helper_class = _helper_class
        self.env = env
            
        # build the TemplateLookup
        super(TemplateLoader, self).__init__(directories=[path], module_directory=CACHE_DIR)
    
    def _render (self, tpl, env, params) :
        """
            Render the given template with given env/params, returning the output as a unicode string, or raising a TemplateError
        """

        # build our Helpers class
        helpers = self.helper_class()

        # build the context from our env, and params
        ctx = dict(
            h       = helpers,
        )
        ctx.update(env)
        ctx.update(params)

        # the buffer to use for unicode output
        buf = util.FastEncodingBuffer(unicode=True)

        # the context to use
        context = Context(buf, **ctx)
        
        # bind our helper
        helpers._bind_ctx(context)
        
        try :
            # render template
            tpl.render_context(context)
        
        # a template may render other templates
        except TemplateError :
            raise

        except :
            # raise a TemplateError with the details
            details = exceptions.text_error_template().render()

            raise TemplateError("Template render failed", status='500 Internal Server Error', details=details)
        
        else :
            # return the unicode data
            return buf.getvalue()

    def lookup (self, name) :
        """
            Looks up a template based on the bare "name", which does not include the path or file extension
        """
        
        try :
            return self.get_template("%s.%s" % (name, self.fileext))

        except :
            raise TemplateError("Template broken: %r" % (name, ), status='500 Internal Server Error', details=exceptions.text_error_template().render())
    
    def render (self, name, **params) :
        """
            Render a template, using lookup() on the given name
        """

        return self._render(self.lookup(name), self.env, params)

    def render_to_response (self, name, **params) :
        """
            Render a template, returning a http.Response object
        """

        return http.Response(self.render(name, **params))

    def load (self, path) :
        """
            Loads a template from a specific file
        """

        try :
            return Template(filename=path, module_directory=CACHE_DIR)

        except :
            raise TemplateError("Template broken: %r" % (path, ), status='500 Internal Server Error', details=exceptions.text_error_template().render())
    
    def render_file (self, path, **params) :
        """
            Render a template, using load() on the given path. No global environment vars are defined for the render.
        """

        return self._render(self.load(path), dict(), params)

    def render_template (self, template, **params) :
        """
            Render the given template object. No global environment vars are defined for the render.
        """
        
        return self._render(template, dict(), params)