Coverage for tw2/core/templating.py : 99%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import os
2from . import core
4from .util import memoize, relpath
6from markupsafe import Markup
7import six
8from six.moves import map
9from six.moves import zip
11# Just shorthand
12SEP, ALTSEP, EXTSEP = os.path.sep, os.path.altsep, os.path.extsep
14engine_name_cache = {}
16_default_rendering_extension_lookup = {
17 'mako': ['mak', 'mako'],
18 'genshi': ['genshi', 'html'],
19 # just for backwards compatibility with tw2 2.0.0
20 'genshi_abs': ['genshi', 'html'],
21 'jinja': ['jinja', 'html'],
22 'chameleon': ['pt'],
23 'kajiki': ['kajiki', 'html'],
24}
27def get_rendering_extensions_lookup(mw):
28 if mw is None:
29 rl = core.request_local()
30 mw = rl.get('middleware')
31 if mw is None:
32 return _default_rendering_extension_lookup
33 return mw.config.rendering_extension_lookup
36@memoize
37def get_engine_name(template_name, mw=None):
38 if template_name in engine_name_cache:
39 return engine_name_cache[template_name]
41 if template_name and ':' in template_name:
42 engine_name = template_name.split(':', 1)[0]
43 engine_name_cache[template_name] = engine_name
44 return engine_name
46 try:
47 if mw is None:
48 rl = core.request_local()
49 mw = rl['middleware']
50 pref_rend_eng = mw.config.preferred_rendering_engines
51 except (KeyError, AttributeError):
52 pref_rend_eng = ['mako', 'genshi', 'jinja', 'chameleon', 'kajiki']
54 # find the first file in the preffered engines available for templating
55 for engine_name in pref_rend_eng:
56 try:
57 get_source(engine_name, template_name, mw=mw)
58 engine_name_cache[template_name] = engine_name
59 return engine_name
60 except IOError:
61 pass
63 if not mw.config.strict_engine_selection:
64 pref_rend_eng = ['mako', 'genshi', 'jinja', 'chameleon', 'kajiki']
65 for engine_name in pref_rend_eng:
66 try:
67 get_source(engine_name, template_name, mw=mw)
68 engine_name_cache[template_name] = engine_name
69 return engine_name
70 except IOError:
71 pass
73 raise ValueError("Could not find engine name for %s" % template_name)
76@memoize
77def _get_dotted_filename(engine_name, template, mw=None):
78 rendering_extension_lookup = get_rendering_extensions_lookup(mw)
79 template = _strip_engine_name(template, mw)
80 location, filename = template.rsplit('.', 1)
81 module = __import__(location, globals(), locals(), ['*'])
82 parent_dir = SEP.join(module.__file__.split(SEP)[:-1])
84 for extension in rendering_extension_lookup[engine_name]:
85 abs_filename = parent_dir + SEP + filename + EXTSEP + extension
86 if os.path.exists(abs_filename):
87 return abs_filename
89 raise IOError("Couldn't find source for %r" % template)
92def _strip_engine_name(template, mw=None):
93 """ Strip off the leading engine name from the template if it exists. """
94 rendering_extension_lookup = get_rendering_extensions_lookup(mw)
95 if any(map(template.lstrip().startswith, rendering_extension_lookup)):
96 return template.split(':', 1)[1]
98 return template
103@memoize
104def get_source(engine_name, template, inline=False, mw=None):
105 if inline:
106 return template
108 if SEP in template or (ALTSEP and ALTSEP in template):
109 filename = _strip_engine_name(template, mw=mw)
110 else:
111 filename = _get_dotted_filename(engine_name, template, mw=mw)
113 with open(filename, 'rb') as f:
114 return f.read().decode('utf-8')
117@memoize
118def get_render_callable(engine_name, displays_on, src, filename=None, inline=False):
119 """ Returns a function that takes a template source and kwargs. """
121 # See the discussion here re: `displays_on` -- http://bit.ly/JRqbRw
123 directory = None
124 if filename and not inline:
125 if SEP not in filename and (not ALTSEP or ALTSEP not in filename):
126 filename = _get_dotted_filename(engine_name, filename)
128 directory = os.path.dirname(filename)
130 if engine_name == 'mako':
131 import mako.template
132 args = dict(text=src, imports=["from markupsafe import escape_silent"],
133 default_filters=['escape_silent'])
135 if directory:
136 args['filename'] = relpath(filename, directory)
137 from mako.lookup import TemplateLookup
138 args['lookup'] = TemplateLookup(
139 directories=[directory])
141 tmpl = mako.template.Template(**args)
142 return lambda kwargs: Markup(tmpl.render_unicode(**kwargs))
144 elif engine_name in ('genshi', 'genshi_abs'):
145 import genshi.template
146 args = dict(
147 source=src,
148 )
150 if directory:
151 args['loader'] = genshi.template.TemplateLoader([
152 genshi.template.loader.directory(directory),
153 ])
155 tmpl = genshi.template.MarkupTemplate(**args)
156 return lambda kwargs: Markup(
157 ''.join(tmpl.generate(**kwargs).serialize('xhtml'))
158 )
160 elif engine_name == 'jinja':
161 import jinja2
162 from .jinja_util import htmlbools
163 env = jinja2.environment.Environment(autoescape=True)
164 env.filters['htmlbools'] = htmlbools
165 tmpl = env.from_string(src, template_class=jinja2.Template)
166 tmpl.filename = filename
167 return lambda kwargs: Markup(tmpl.render(**kwargs))
169 elif engine_name == 'kajiki':
170 import kajiki
171 tmpl = kajiki.XMLTemplate(src, filename=filename,
172 cdata_scripts=False)
173 return lambda kwargs: Markup(tmpl(kwargs).render())
175 elif engine_name == 'chameleon':
176 import chameleon
177 tmpl = chameleon.PageTemplate(src, filename=filename)
178 return lambda kwargs: Markup(tmpl.render(**kwargs).strip())
180 raise NotImplementedError("Unhandled engine")
183def render(template_name, displays_on, kwargs, inline=False, mw=None):
184 """ Highest level function, here for convenience.
186 Makes use of *all* other functions in this module.
187 """
189 # Determine the engine name
190 if not inline:
191 engine_name = get_engine_name(template_name, mw)
192 else:
193 engine_name = inline
195 if mw is not None and mw.config.auto_reload_templates:
196 get_source._flush()
197 get_render_callable._flush()
199 # Load the template source
200 source = get_source(engine_name, template_name, inline, mw)
202 # Establish the render function
203 callback = get_render_callable(
204 engine_name, displays_on, source, template_name, inline)
206 # Do it
207 return callback(kwargs)