terom@8: """ terom@8: Template handler terom@8: """ terom@8: terom@50: from mako import exceptions, util terom@50: from mako.runtime import Context terom@8: from mako.template import Template terom@32: import mako.lookup terom@8: terom@46: from qmsk.web import http, helpers terom@26: terom@8: # path to template files terom@8: TEMPLATE_DIR = "templates" terom@8: terom@8: # path to cached templates terom@8: CACHE_DIR = "cache/templates" terom@8: terom@8: # template file extension terom@8: TEMPLATE_EXT = "tmpl" terom@8: terom@70: class TemplateError (Exception) : terom@8: """ terom@8: Raised by the template module functions terom@8: """ terom@8: terom@8: pass terom@8: terom@71: def fmt_mako_exception () : terom@71: """ terom@71: Returns a string containing the Mako-ized error traceback (so that it includes the template data) terom@71: """ terom@71: terom@71: return exceptions.text_error_template().render() terom@71: terom@32: class TemplateLoader (mako.lookup.TemplateLookup) : terom@8: """ terom@32: Our own specialization of mako's TemplateLookup terom@8: """ terom@8: terom@50: def __init__ (self, path, fileext=TEMPLATE_EXT, _helper_class=helpers.Helpers, **env) : terom@32: """ terom@42: Initialize to load templates located at path, with the given file extension. terom@42: terom@50: The given Helpers class is used to provide the helper methods terom@50: terom@42: The given **env list is supplied to every template render terom@32: """ terom@8: terom@32: # store terom@32: self.path = path terom@32: self.fileext = fileext terom@50: self.helper_class = _helper_class terom@42: self.env = env terom@42: terom@42: # build the TemplateLookup terom@42: super(TemplateLoader, self).__init__(directories=[path], module_directory=CACHE_DIR) terom@42: terom@50: def _render (self, tpl, env, params) : terom@42: """ terom@42: Render the given template with given env/params, returning the output as a unicode string, or raising a TemplateError terom@42: """ terom@42: terom@50: # build our Helpers class terom@50: helpers = self.helper_class() terom@50: terom@50: # build the context from our env, and params terom@42: ctx = dict( terom@42: h = helpers, terom@42: ) terom@42: ctx.update(env) terom@42: ctx.update(params) terom@42: terom@50: # the buffer to use for unicode output terom@50: buf = util.FastEncodingBuffer(unicode=True) terom@50: terom@50: # the context to use terom@50: context = Context(buf, **ctx) terom@50: terom@50: # bind our helper terom@50: helpers._bind_ctx(context) terom@50: terom@42: try : terom@50: # render template terom@50: tpl.render_context(context) terom@32: terom@42: # a template may render other templates terom@42: except TemplateError : terom@42: raise terom@42: terom@42: except : terom@50: # raise a TemplateError with the details terom@71: raise TemplateError("tpl=%r, params=%r: %s" % (tpl, params, fmt_mako_exception())) terom@50: terom@50: else : terom@50: # return the unicode data terom@50: return buf.getvalue() terom@8: terom@32: def lookup (self, name) : terom@32: """ terom@32: Looks up a template based on the bare "name", which does not include the path or file extension terom@32: """ terom@32: terom@32: try : terom@32: return self.get_template("%s.%s" % (name, self.fileext)) terom@8: terom@32: except : terom@71: raise TemplateError("name=%r: %s" % (name, fmt_mako_exception())) terom@32: terom@40: def render (self, name, **params) : terom@32: """ terom@32: Render a template, using lookup() on the given name terom@32: """ terom@32: terom@42: return self._render(self.lookup(name), self.env, params) terom@32: terom@40: def render_to_response (self, name, **params) : terom@40: """ terom@40: Render a template, returning a http.Response object terom@40: """ terom@40: terom@40: return http.Response(self.render(name, **params)) terom@40: terom@50: def load (self, path) : terom@32: """ terom@32: Loads a template from a specific file terom@32: """ terom@32: terom@32: try : terom@32: return Template(filename=path, module_directory=CACHE_DIR) terom@32: terom@32: except : terom@71: raise TemplateError("path=%r: %s" % (path, fmt_mako_exception())) terom@32: terom@50: def render_file (self, path, **params) : terom@32: """ terom@42: Render a template, using load() on the given path. No global environment vars are defined for the render. terom@32: """ terom@32: terom@50: return self._render(self.load(path), dict(), params) terom@32: terom@50: def render_template (self, template, **params) : terom@42: """ terom@42: Render the given template object. No global environment vars are defined for the render. terom@42: """ terom@42: terom@50: return self._render(template, dict(), params) terom@50: