template.py
author Tero Marttila <terom@fixme.fi>
Mon, 16 Feb 2009 19:08:17 +0200
changeset 78 a46d2fc07951
parent 71 0162c2b21dc5
permissions -rw-r--r--
add test for tree_parse filesystem stuff
"""
    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 (Exception) :
    """
        Raised by the template module functions
    """

    pass

def fmt_mako_exception () :
    """
        Returns a string containing the Mako-ized error traceback (so that it includes the template data)
    """

    return exceptions.text_error_template().render()
 
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
            raise TemplateError("tpl=%r, params=%r: %s" % (tpl, params, fmt_mako_exception()))
        
        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("name=%r: %s" % (name, fmt_mako_exception()))
    
    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("path=%r: %s" % (path, fmt_mako_exception()))
    
    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)