comparison piecrust/templating/jinjaengine.py @ 907:3e69f18912f5

jinja: Remove Twig compatibility, add timer, improve code. - Add a timer for keeping track of extensions' performance. - Use the `select_template` function from Jinja to cut down on a few lines of code.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 23 Jul 2017 08:30:47 -0700
parents 5c5b85d4f17d
children 1bb704434ee2
comparison
equal deleted inserted replaced
906:1c6a4d2ec16e 907:3e69f18912f5
7 7
8 logger = logging.getLogger(__name__) 8 logger = logging.getLogger(__name__)
9 9
10 10
11 class JinjaTemplateEngine(TemplateEngine): 11 class JinjaTemplateEngine(TemplateEngine):
12 # Name `twig` is for backwards compatibility with PieCrust 1.x. 12 ENGINE_NAMES = ['jinja', 'jinja2', 'j2']
13 ENGINE_NAMES = ['jinja', 'jinja2', 'j2', 'twig'] 13 EXTENSIONS = ['html', 'jinja', 'jinja2', 'j2']
14 EXTENSIONS = ['html', 'jinja', 'jinja2', 'j2', 'twig']
15 14
16 def __init__(self): 15 def __init__(self):
17 self.env = None 16 self.env = None
18 self._jinja_syntax_error = None 17 self._jinja_syntax_error = None
19 self._jinja_not_found = None 18 self._jinja_not_found = None
20 19
21 def renderSegmentPart(self, path, seg_part, data): 20 def renderSegmentPart(self, path, seg_part, data):
22 self._ensureLoaded()
23
24 if not _string_needs_render(seg_part.content): 21 if not _string_needs_render(seg_part.content):
25 return seg_part.content 22 return seg_part.content
23
24 self._ensureLoaded()
26 25
27 part_path = _make_segment_part_path(path, seg_part.offset) 26 part_path = _make_segment_part_path(path, seg_part.offset)
28 self.env.loader.segment_parts_cache[part_path] = ( 27 self.env.loader.segment_parts_cache[part_path] = (
29 path, seg_part.content) 28 path, seg_part.content)
30 try: 29 try:
47 rel_path = os.path.relpath(path, self.app.root_dir) 46 rel_path = os.path.relpath(path, self.app.root_dir)
48 raise TemplatingError(msg, rel_path) from ex 47 raise TemplatingError(msg, rel_path) from ex
49 48
50 def renderFile(self, paths, data): 49 def renderFile(self, paths, data):
51 self._ensureLoaded() 50 self._ensureLoaded()
52 tpl = None
53 logger.debug("Looking for template: %s" % paths)
54 rendered_path = None
55 for p in paths:
56 try:
57 tpl = self.env.get_template(p)
58 rendered_path = p
59 break
60 except self._jinja_syntax_error as tse:
61 raise self._getTemplatingError(tse)
62 except self._jinja_not_found:
63 pass
64 51
65 if tpl is None: 52 try:
53 tpl = self.env.select_template(paths)
54 except self._jinja_syntax_error as tse:
55 raise self._getTemplatingError(tse)
56 except self._jinja_not_found:
66 raise TemplateNotFoundError() 57 raise TemplateNotFoundError()
67 58
68 try: 59 try:
69 return tpl.render(data) 60 return tpl.render(data)
70 except self._jinja_syntax_error as tse: 61 except self._jinja_syntax_error as tse:
73 raise 64 raise
74 except Exception as ex: 65 except Exception as ex:
75 if self.app.debug: 66 if self.app.debug:
76 raise 67 raise
77 msg = "Error rendering Jinja markup" 68 msg = "Error rendering Jinja markup"
78 rel_path = os.path.relpath(rendered_path, self.app.root_dir) 69 name = getattr(tpl, 'name', '<unknown template>')
79 raise TemplatingError(msg, rel_path) from ex 70 raise TemplatingError(msg, name) from ex
80 71
81 def _getTemplatingError(self, tse, filename=None): 72 def _getTemplatingError(self, tse, filename=None):
82 filename = tse.filename or filename 73 filename = tse.filename or filename
83 if filename and os.path.isabs(filename): 74 if filename and os.path.isabs(filename):
84 filename = os.path.relpath(filename, self.env.app.root_dir) 75 filename = os.path.relpath(filename, self.env.app.root_dir)
88 def _ensureLoaded(self): 79 def _ensureLoaded(self):
89 if self.env is not None: 80 if self.env is not None:
90 return 81 return
91 82
92 stats = self.app.env.stats 83 stats = self.app.env.stats
93 stats.registerTimer('JinjaTemplateEngineEnvironmentSetup', 84 stats.registerTimer('JinjaTemplateEngine_setup',
94 raise_if_registered=False) 85 raise_if_registered=False)
95 with stats.timerScope('JinjaTemplateEngineEnvironmentSetup'): 86 stats.registerTimer('JinjaTemplateEngine_extensions',
87 raise_if_registered=False)
88 with stats.timerScope('JinjaTemplateEngine_setup'):
96 self._load() 89 self._load()
97 90
98 def _load(self): 91 def _load(self):
99 get_config = self.app.config.get 92 get_config = self.app.config.get
100 93
102 ext_names = get_config('jinja/extensions', []) 95 ext_names = get_config('jinja/extensions', [])
103 if not isinstance(ext_names, list): 96 if not isinstance(ext_names, list):
104 ext_names = [ext_names] 97 ext_names = [ext_names]
105 98
106 # Turn on autoescape by default. 99 # Turn on autoescape by default.
107 autoescape = get_config('twig/auto_escape') 100 autoescape = get_config('jinja/auto_escape', True)
108 if autoescape is not None:
109 logger.warning("The `twig/auto_escape` setting is now called "
110 "`jinja/auto_escape`.")
111 else:
112 autoescape = get_config('jinja/auto_escape', True)
113 if autoescape: 101 if autoescape:
114 ext_names.append('autoescape') 102 ext_names.append('autoescape')
115 103
116 # Create the final list of extensions. 104 # Create the final list of extensions.
117 from piecrust.templating.jinja.extensions import ( 105 from piecrust.templating.jinja.extensions import (
158 146
159 147
160 def _make_segment_part_path(path, start): 148 def _make_segment_part_path(path, start):
161 return '$part=%s:%d' % (path, start) 149 return '$part=%s:%d' % (path, start)
162 150
163