terom@150: """ terom@150: Template handler terom@150: """ terom@150: terom@150: # use Mako terom@150: from mako import exceptions terom@150: from mako.template import Template terom@173: import mako.lookup terom@150: terom@150: # for http.ResponseError terom@150: import http terom@150: terom@167: import helpers terom@167: terom@150: # path to template files terom@150: TEMPLATE_DIR = "templates" terom@150: terom@150: # path to cached templates terom@150: CACHE_DIR = "cache/templates" terom@150: terom@150: # template file extension terom@150: TEMPLATE_EXT = "tmpl" terom@150: terom@150: class TemplateError (http.ResponseError) : terom@150: """ terom@150: Raised by the template module functions terom@150: """ terom@150: terom@150: pass terom@150: terom@173: def render (tpl, **params) : terom@150: """ terom@163: Render the given template, returning the output as a unicode string, or raising a TemplateError terom@150: """ terom@150: terom@150: try : terom@167: return tpl.render_unicode( terom@167: # global helper stuff terom@167: h = helpers, terom@167: terom@167: # render-specific params terom@167: **params terom@167: ) terom@153: terom@153: # a template may render other templates terom@153: except TemplateError : terom@153: raise terom@150: terom@150: except : terom@153: details = exceptions.text_error_template().render() terom@153: terom@153: raise TemplateError("Template render failed", status='500 Internal Server Error', details=details) terom@150: terom@173: class TemplateLoader (mako.lookup.TemplateLookup) : terom@150: """ terom@173: Our own specialization of mako's TemplateLookup terom@150: """ terom@150: terom@173: def __init__ (self, path, fileext=TEMPLATE_EXT) : terom@173: """ terom@173: Initialize to load templates located at path, with the given file extension terom@173: """ terom@150: terom@173: # store terom@173: self.path = path terom@173: self.fileext = fileext terom@173: terom@173: # XXX: separate cache? terom@173: super(TemplateLoader, self).__init__(directories=[path], module_directory=CACHE_DIR) terom@150: terom@173: def lookup (self, name) : terom@173: """ terom@173: Looks up a template based on the bare "name", which does not include the path or file extension terom@173: """ terom@173: terom@173: try : terom@173: return self.get_template("%s.%s" % (name, self.fileext)) terom@150: terom@173: except : terom@173: raise TemplateError("Template broken: %r" % (name, ), status='500 Internal Server Error', details=exceptions.text_error_template().render()) terom@173: terom@181: def render (self, name, **params) : terom@173: """ terom@173: Render a template, using lookup() on the given name terom@173: """ terom@173: terom@173: return render(self.lookup(name), **params) terom@173: terom@181: def render_to_response (self, name, **params) : terom@181: """ terom@181: Render a template, returning a http.Response object terom@181: """ terom@181: terom@181: return http.Response(self.render(name, **params)) terom@181: terom@173: @classmethod terom@173: def load (cls, path) : terom@173: """ terom@173: Loads a template from a specific file terom@173: """ terom@173: terom@173: try : terom@173: return Template(filename=path, module_directory=CACHE_DIR) terom@173: terom@173: except : terom@173: raise TemplateError("Template broken: %r" % (path, ), status='500 Internal Server Error', details=exceptions.text_error_template().render()) terom@173: terom@173: @classmethod terom@173: def render_file (cls, path, **params) : terom@173: """ terom@173: Render a template, using load() on the given path terom@173: """ terom@173: terom@173: return render(cls.load(path), **params) terom@173: terom@173: