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