Home | History | Annotate | Download | only in webapp2_extras
      1 # -*- coding: utf-8 -*-
      2 """
      3     webapp2_extras.mako
      4     ===================
      5 
      6     Mako template support for webapp2.
      7 
      8     Learn more about Mako: http://www.makotemplates.org/
      9 
     10     :copyright: 2011 by tipfy.org.
     11     :license: Apache Sotware License, see LICENSE for details.
     12 """
     13 from __future__ import absolute_import
     14 
     15 from mako import lookup
     16 
     17 import webapp2
     18 
     19 #: Default configuration values for this module. Keys are:
     20 #:
     21 #: template_path
     22 #:     Directory for templates. Default is `templates`.
     23 default_config = {
     24     'template_path': 'templates',
     25 }
     26 
     27 
     28 class Mako(object):
     29     """Wrapper for configurable and cached Mako environment.
     30 
     31     To used it, set it as a cached property in a base `RequestHandler`::
     32 
     33         import webapp2
     34 
     35         from webapp2_extras import mako
     36 
     37         class BaseHandler(webapp2.RequestHandler):
     38 
     39             @webapp2.cached_property
     40             def mako(self):
     41                 # Returns a Mako renderer cached in the app registry.
     42                 return mako.get_mako(app=self.app)
     43 
     44             def render_response(self, _template, **context):
     45                 # Renders a template and writes the result to the response.
     46                 rv = self.mako.render_template(_template, **context)
     47                 self.response.write(rv)
     48 
     49     Then extended handlers can render templates directly::
     50 
     51         class MyHandler(BaseHandler):
     52             def get(self):
     53                 context = {'message': 'Hello, world!'}
     54                 self.render_response('my_template.html', **context)
     55     """
     56 
     57     #: Configuration key.
     58     config_key = __name__
     59 
     60     #: Loaded configuration.
     61     config = None
     62 
     63     def __init__(self, app, config=None):
     64         self.config = config = app.config.load_config(self.config_key,
     65             default_values=default_config, user_values=config,
     66             required_keys=None)
     67 
     68         directories = config.get('template_path')
     69         if isinstance(directories, basestring):
     70             directories = [directories]
     71 
     72         self.environment = lookup.TemplateLookup(directories=directories,
     73                                                  output_encoding='utf-8',
     74                                                  encoding_errors='replace')
     75 
     76     def render_template(self, _filename, **context):
     77         """Renders a template and returns a response object.
     78 
     79         :param _filename:
     80             The template filename, related to the templates directory.
     81         :param context:
     82             Keyword arguments used as variables in the rendered template.
     83             These will override values set in the request context.
     84         :returns:
     85             A rendered template.
     86         """
     87         template = self.environment.get_template(_filename)
     88         return template.render_unicode(**context)
     89 
     90 
     91 # Factories -------------------------------------------------------------------
     92 
     93 
     94 #: Key used to store :class:`Mako` in the app registry.
     95 _registry_key = 'webapp2_extras.mako.Mako'
     96 
     97 
     98 def get_mako(factory=Mako, key=_registry_key, app=None):
     99     """Returns an instance of :class:`Mako` from the app registry.
    100 
    101     It'll try to get it from the current app registry, and if it is not
    102     registered it'll be instantiated and registered. A second call to this
    103     function will return the same instance.
    104 
    105     :param factory:
    106         The callable used to build and register the instance if it is not yet
    107         registered. The default is the class :class:`Mako` itself.
    108     :param key:
    109         The key used to store the instance in the registry. A default is used
    110         if it is not set.
    111     :param app:
    112         A :class:`webapp2.WSGIApplication` instance used to store the instance.
    113         The active app is used if it is not set.
    114     """
    115     app = app or webapp2.get_app()
    116     mako = app.registry.get(key)
    117     if not mako:
    118         mako = app.registry[key] = factory(app)
    119 
    120     return mako
    121 
    122 
    123 def set_mako(mako, key=_registry_key, app=None):
    124     """Sets an instance of :class:`Mako` in the app registry.
    125 
    126     :param store:
    127         An instance of :class:`Mako`.
    128     :param key:
    129         The key used to retrieve the instance from the registry. A default
    130         is used if it is not set.
    131     :param request:
    132         A :class:`webapp2.WSGIApplication` instance used to retrieve the
    133         instance. The active app is used if it is not set.
    134     """
    135     app = app or webapp2.get_app()
    136     app.registry[key] = mako
    137