Mercurial > piecrust2
comparison piecrust/templating/pystacheengine.py @ 850:370e74941d32
optimize: Only load some 3rd party packages when needed.
This commit only optimizes the Markdown, SmartyPants, and Pystache wrappers.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sat, 29 Apr 2017 21:27:33 -0700 |
parents | 9d1a89cd8146 |
children | 1bb704434ee2 |
comparison
equal
deleted
inserted
replaced
849:8f8bbb2e70e1 | 850:370e74941d32 |
---|---|
1 import logging | 1 import logging |
2 import collections.abc | 2 import collections.abc |
3 import pystache | |
4 import pystache.common | |
5 from piecrust.templating.base import ( | 3 from piecrust.templating.base import ( |
6 TemplateEngine, TemplateNotFoundError, TemplatingError) | 4 TemplateEngine, TemplateNotFoundError, TemplatingError) |
7 | 5 |
8 | 6 |
9 logger = logging.getLogger(__name__) | 7 logger = logging.getLogger(__name__) |
10 | 8 |
11 | 9 |
13 ENGINE_NAMES = ['mustache'] | 11 ENGINE_NAMES = ['mustache'] |
14 EXTENSIONS = ['mustache'] | 12 EXTENSIONS = ['mustache'] |
15 | 13 |
16 def __init__(self): | 14 def __init__(self): |
17 self.renderer = None | 15 self.renderer = None |
16 self._not_found_error = None | |
17 self._pystache_error = None | |
18 | 18 |
19 def renderSegmentPart(self, path, seg_part, data): | 19 def renderSegmentPart(self, path, seg_part, data): |
20 self._ensureLoaded() | 20 self._ensureLoaded() |
21 try: | 21 try: |
22 return self.renderer.render(seg_part.content, data) | 22 return self.renderer.render(seg_part.content, data) |
23 except pystache.common.TemplateNotFoundError as ex: | 23 except self._not_found_error as ex: |
24 raise TemplateNotFoundError() from ex | 24 raise TemplateNotFoundError() from ex |
25 except pystache.common.PystacheError as ex: | 25 except self._pystache_error as ex: |
26 raise TemplatingError(str(ex), path) from ex | 26 raise TemplatingError(str(ex), path) from ex |
27 | 27 |
28 def renderFile(self, paths, data): | 28 def renderFile(self, paths, data): |
29 self._ensureLoaded() | 29 self._ensureLoaded() |
30 tpl = None | 30 tpl = None |
31 logger.debug("Looking for template: %s" % paths) | 31 logger.debug("Looking for template: %s" % paths) |
32 for p in paths: | 32 for p in paths: |
33 if not p.endswith('.mustache'): | 33 if not p.endswith('.mustache'): |
34 raise TemplatingError( | 34 raise TemplatingError( |
35 "The Mustache template engine only accepts template " | 35 "The Mustache template engine only accepts template " |
36 "filenames with a `.mustache` extension. Got: %s" % | 36 "filenames with a `.mustache` extension. Got: %s" % |
37 p) | 37 p) |
38 name = p[:-9] # strip `.mustache` | 38 name = p[:-9] # strip `.mustache` |
39 try: | 39 try: |
40 tpl = self.renderer.load_template(name) | 40 tpl = self.renderer.load_template(name) |
41 except Exception as ex: | 41 except Exception as ex: |
42 logger.debug("Mustache error: %s" % ex) | 42 logger.debug("Mustache error: %s" % ex) |
45 if tpl is None: | 45 if tpl is None: |
46 raise TemplateNotFoundError() | 46 raise TemplateNotFoundError() |
47 | 47 |
48 try: | 48 try: |
49 return self.renderer.render(tpl, data) | 49 return self.renderer.render(tpl, data) |
50 except pystache.common.PystacheError as ex: | 50 except self._pystache_error as ex: |
51 raise TemplatingError(str(ex)) from ex | 51 raise TemplatingError(str(ex)) from ex |
52 | 52 |
53 def _ensureLoaded(self): | 53 def _ensureLoaded(self): |
54 if self.renderer: | 54 if self.renderer: |
55 return | 55 return |
56 | 56 |
57 import pystache | |
58 import pystache.common | |
59 | |
60 self._not_found_error = pystache.common.TemplateNotFoundError | |
61 self._pystache_error = pystache.common.PystacheError | |
62 | |
63 class _WorkaroundRenderer(pystache.Renderer): | |
64 def _make_resolve_context(self): | |
65 mrc = super(_WorkaroundRenderer, self)._make_resolve_context() | |
66 | |
67 def _workaround(stack, name): | |
68 # Pystache will treat anything that's not a string or | |
69 # a dict as a list. This is just plain wrong, but it will | |
70 # take a while before the project can get patches on Pypi. | |
71 res = mrc(stack, name) | |
72 if res is not None and ( | |
73 res.__class__.__name__ in _knowns or | |
74 isinstance(res, collections.abc.Mapping)): | |
75 res = [res] | |
76 return res | |
77 | |
78 return _workaround | |
79 | |
57 self.renderer = _WorkaroundRenderer( | 80 self.renderer = _WorkaroundRenderer( |
58 search_dirs=self.app.templates_dirs) | 81 search_dirs=self.app.templates_dirs) |
59 | 82 |
60 | 83 |
61 _knowns = ['PieCrustData', 'LazyPageConfigData', 'Paginator', 'Assetor', | 84 _knowns = ['PieCrustData', 'LazyPageConfigData', 'Paginator', 'Assetor', |
62 'PageLinkerData'] | 85 'PageLinkerData'] |
63 | |
64 | |
65 class _WorkaroundRenderer(pystache.Renderer): | |
66 def _make_resolve_context(self): | |
67 mrc = super(_WorkaroundRenderer, self)._make_resolve_context() | |
68 | |
69 def _workaround(stack, name): | |
70 # Pystache will treat anything that's not a string or a dict as | |
71 # a list. This is just plain wrong, but it will take a while before | |
72 # the project can get patches on Pypi. | |
73 res = mrc(stack, name) | |
74 if res is not None and ( | |
75 res.__class__.__name__ in _knowns or | |
76 isinstance(res, collections.abc.Mapping)): | |
77 res = [res] | |
78 return res | |
79 | |
80 return _workaround | |
81 |