annotate piecrust/templating/pystacheengine.py @ 1188:a7c43131d871

bake: Fix file write flushing problem with Python 3.8+ Writing the cache files fails in Python 3.8 because it looks like flushing behaviour has changed. We need to explicitly flush. And even then, in very rare occurrences, it looks like it can still run into racing conditions, so we do a very hacky and ugly "retry" loop when fetching cached data :(
author Ludovic Chabant <ludovic@chabant.com>
date Tue, 15 Jun 2021 22:36:23 -0700
parents 8adc27285d93
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
1 import logging
440
32c7c2d219d2 performance: Refactor how data is managed to reduce copying.
Ludovic Chabant <ludovic@chabant.com>
parents: 429
diff changeset
2 import collections.abc
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
3 from piecrust.templating.base import (
850
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
4 TemplateEngine, TemplateNotFoundError, TemplatingError)
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
5
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
6
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
7 logger = logging.getLogger(__name__)
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
8
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
9
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
10 class PystacheTemplateEngine(TemplateEngine):
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
11 ENGINE_NAMES = ['mustache']
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
12 EXTENSIONS = ['mustache']
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
13
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
14 def __init__(self):
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
15 self.renderer = None
850
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
16 self._not_found_error = None
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
17 self._pystache_error = None
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
18
924
1bb704434ee2 formatting: Remove segment parts, you can use template tags instead.
Ludovic Chabant <ludovic@chabant.com>
parents: 850
diff changeset
19 def renderSegment(self, path, segment, data):
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
20 self._ensureLoaded()
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
21 try:
989
8adc27285d93 bake: Big pass on bake performance.
Ludovic Chabant <ludovic@chabant.com>
parents: 924
diff changeset
22 return self.renderer.render(segment.content, data), True
850
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
23 except self._not_found_error as ex:
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
24 raise TemplateNotFoundError() from ex
850
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
25 except self._pystache_error as ex:
454
96d363e2da4b templating: Let Jinja2 cache the parsed template for page contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 440
diff changeset
26 raise TemplatingError(str(ex), path) from ex
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
27
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
28 def renderFile(self, paths, data):
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
29 self._ensureLoaded()
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
30 tpl = None
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
31 logger.debug("Looking for template: %s" % paths)
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
32 for p in paths:
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
33 if not p.endswith('.mustache'):
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
34 raise TemplatingError(
850
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
35 "The Mustache template engine only accepts template "
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
36 "filenames with a `.mustache` extension. Got: %s" %
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
37 p)
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
38 name = p[:-9] # strip `.mustache`
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
39 try:
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
40 tpl = self.renderer.load_template(name)
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
41 except Exception as ex:
519
9d1a89cd8146 cosmetic: Remove debug print here too.
Ludovic Chabant <ludovic@chabant.com>
parents: 454
diff changeset
42 logger.debug("Mustache error: %s" % ex)
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
43 pass
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
44
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
45 if tpl is None:
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
46 raise TemplateNotFoundError()
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
47
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
48 try:
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
49 return self.renderer.render(tpl, data)
850
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
50 except self._pystache_error as ex:
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
51 raise TemplatingError(str(ex)) from ex
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
52
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
53 def _ensureLoaded(self):
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
54 if self.renderer:
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
55 return
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
56
850
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
57 import pystache
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
58 import pystache.common
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
59
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
60 self._not_found_error = pystache.common.TemplateNotFoundError
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
61 self._pystache_error = pystache.common.PystacheError
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
62
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
63 class _WorkaroundRenderer(pystache.Renderer):
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
64 def _make_resolve_context(self):
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
65 mrc = super(_WorkaroundRenderer, self)._make_resolve_context()
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
66
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
67 def _workaround(stack, name):
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
68 # Pystache will treat anything that's not a string or
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
69 # a dict as a list. This is just plain wrong, but it will
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
70 # take a while before the project can get patches on Pypi.
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
71 res = mrc(stack, name)
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
72 if res is not None and (
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
73 res.__class__.__name__ in _knowns or
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
74 isinstance(res, collections.abc.Mapping)):
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
75 res = [res]
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
76 return res
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
77
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
78 return _workaround
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
79
429
ca5a3c970263 templating: Workaround for a bug with Pystache.
Ludovic Chabant <ludovic@chabant.com>
parents: 428
diff changeset
80 self.renderer = _WorkaroundRenderer(
850
370e74941d32 optimize: Only load some 3rd party packages when needed.
Ludovic Chabant <ludovic@chabant.com>
parents: 519
diff changeset
81 search_dirs=self.app.templates_dirs)
185
139179dc7abd render: Add support for a Mustache template engine.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
82
429
ca5a3c970263 templating: Workaround for a bug with Pystache.
Ludovic Chabant <ludovic@chabant.com>
parents: 428
diff changeset
83
ca5a3c970263 templating: Workaround for a bug with Pystache.
Ludovic Chabant <ludovic@chabant.com>
parents: 428
diff changeset
84 _knowns = ['PieCrustData', 'LazyPageConfigData', 'Paginator', 'Assetor',
ca5a3c970263 templating: Workaround for a bug with Pystache.
Ludovic Chabant <ludovic@chabant.com>
parents: 428
diff changeset
85 'PageLinkerData']