lib/template.py
author Tero Marttila <terom@fixme.fi>
Sun, 08 Feb 2009 02:29:23 +0200
branchsites
changeset 42 5a72c00c4ae4
parent 40 71ab68f31a1c
permissions -rw-r--r--
more fiddling around with the irclogs layout/css, add query args to URL
"""
    Template handler
"""

# use Mako
from mako import exceptions
from mako.template import Template
import mako.lookup

# for http.ResponseError
import http

import 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, **env) :
        """
            Initialize to load templates located at path, with the given file extension.

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

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

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

        try :
            return tpl.render_unicode(**ctx)
        
        # a template may render other templates
        except TemplateError :
            raise

        except :
            details = exceptions.text_error_template().render()

            raise TemplateError("Template render failed", status='500 Internal Server Error', details=details)


    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))

    @classmethod
    def load (cls, 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())
    
    @classmethod
    def render_file (cls, path, **params) :
        """
            Render a template, using load() on the given path. No global environment vars are defined for the render.
        """

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

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