template.py
author Tero Marttila <terom@fixme.fi>
Mon, 16 Feb 2009 19:02:59 +0200
changeset 77 bef7196f7682
parent 71 0162c2b21dc5
permissions -rw-r--r--
add tree_parse test and fix treeparse to handle other than filesystem paths
"""
    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)