1 """ |
|
2 Template handler |
|
3 """ |
|
4 |
|
5 # use Mako |
|
6 from mako import exceptions |
|
7 from mako.template import Template |
|
8 import mako.lookup |
|
9 |
|
10 # for http.ResponseError |
|
11 import http |
|
12 |
|
13 import helpers |
|
14 |
|
15 # path to template files |
|
16 TEMPLATE_DIR = "templates" |
|
17 |
|
18 # path to cached templates |
|
19 CACHE_DIR = "cache/templates" |
|
20 |
|
21 # template file extension |
|
22 TEMPLATE_EXT = "tmpl" |
|
23 |
|
24 class TemplateError (http.ResponseError) : |
|
25 """ |
|
26 Raised by the template module functions |
|
27 """ |
|
28 |
|
29 pass |
|
30 |
|
31 class TemplateLoader (mako.lookup.TemplateLookup) : |
|
32 """ |
|
33 Our own specialization of mako's TemplateLookup |
|
34 """ |
|
35 |
|
36 def __init__ (self, path, fileext=TEMPLATE_EXT, **env) : |
|
37 """ |
|
38 Initialize to load templates located at path, with the given file extension. |
|
39 |
|
40 The given **env list is supplied to every template render |
|
41 """ |
|
42 |
|
43 # store |
|
44 self.path = path |
|
45 self.fileext = fileext |
|
46 self.env = env |
|
47 |
|
48 # build the TemplateLookup |
|
49 super(TemplateLoader, self).__init__(directories=[path], module_directory=CACHE_DIR) |
|
50 |
|
51 @staticmethod |
|
52 def _render (tpl, env, params) : |
|
53 """ |
|
54 Render the given template with given env/params, returning the output as a unicode string, or raising a TemplateError |
|
55 """ |
|
56 |
|
57 # build the context from our superglobals, env, and params |
|
58 ctx = dict( |
|
59 h = helpers, |
|
60 ) |
|
61 ctx.update(env) |
|
62 ctx.update(params) |
|
63 |
|
64 try : |
|
65 return tpl.render_unicode(**ctx) |
|
66 |
|
67 # a template may render other templates |
|
68 except TemplateError : |
|
69 raise |
|
70 |
|
71 except : |
|
72 details = exceptions.text_error_template().render() |
|
73 |
|
74 raise TemplateError("Template render failed", status='500 Internal Server Error', details=details) |
|
75 |
|
76 |
|
77 def lookup (self, name) : |
|
78 """ |
|
79 Looks up a template based on the bare "name", which does not include the path or file extension |
|
80 """ |
|
81 |
|
82 try : |
|
83 return self.get_template("%s.%s" % (name, self.fileext)) |
|
84 |
|
85 except : |
|
86 raise TemplateError("Template broken: %r" % (name, ), status='500 Internal Server Error', details=exceptions.text_error_template().render()) |
|
87 |
|
88 def render (self, name, **params) : |
|
89 """ |
|
90 Render a template, using lookup() on the given name |
|
91 """ |
|
92 |
|
93 return self._render(self.lookup(name), self.env, params) |
|
94 |
|
95 def render_to_response (self, name, **params) : |
|
96 """ |
|
97 Render a template, returning a http.Response object |
|
98 """ |
|
99 |
|
100 return http.Response(self.render(name, **params)) |
|
101 |
|
102 @classmethod |
|
103 def load (cls, path) : |
|
104 """ |
|
105 Loads a template from a specific file |
|
106 """ |
|
107 |
|
108 try : |
|
109 return Template(filename=path, module_directory=CACHE_DIR) |
|
110 |
|
111 except : |
|
112 raise TemplateError("Template broken: %r" % (path, ), status='500 Internal Server Error', details=exceptions.text_error_template().render()) |
|
113 |
|
114 @classmethod |
|
115 def render_file (cls, path, **params) : |
|
116 """ |
|
117 Render a template, using load() on the given path. No global environment vars are defined for the render. |
|
118 """ |
|
119 |
|
120 return cls._render(cls.load(path), dict(), params) |
|
121 |
|
122 @classmethod |
|
123 def render_template (cls, template, **params) : |
|
124 """ |
|
125 Render the given template object. No global environment vars are defined for the render. |
|
126 """ |
|
127 |
|
128 return cls._render(template, dict(), params) |
|