view piecrust/templating/pystacheengine.py @ 661:2f780b191541

internal: Fix a bug with registering taxonomy terms that are not strings. Some objects, like the blog data provider's taxnonomy entries, can render as strings, but are objects themselves. When registering them as "used terms", we need to use their string representation.
author Ludovic Chabant <ludovic@chabant.com>
date Tue, 01 Mar 2016 22:26:09 -0800
parents 9d1a89cd8146
children 370e74941d32
line wrap: on
line source

import logging
import collections.abc
import pystache
import pystache.common
from piecrust.templating.base import (
        TemplateEngine, TemplateNotFoundError, TemplatingError)


logger = logging.getLogger(__name__)


class PystacheTemplateEngine(TemplateEngine):
    ENGINE_NAMES = ['mustache']
    EXTENSIONS = ['mustache']

    def __init__(self):
        self.renderer = None

    def renderSegmentPart(self, path, seg_part, data):
        self._ensureLoaded()
        try:
            return self.renderer.render(seg_part.content, data)
        except pystache.common.TemplateNotFoundError as ex:
            raise TemplateNotFoundError() from ex
        except pystache.common.PystacheError as ex:
            raise TemplatingError(str(ex), path) from ex

    def renderFile(self, paths, data):
        self._ensureLoaded()
        tpl = None
        logger.debug("Looking for template: %s" % paths)
        for p in paths:
            if not p.endswith('.mustache'):
                raise TemplatingError(
                        "The Mustache template engine only accepts template "
                        "filenames with a `.mustache` extension. Got: %s" %
                        p)
            name = p[:-9]  # strip `.mustache`
            try:
                tpl = self.renderer.load_template(name)
            except Exception as ex:
                logger.debug("Mustache error: %s" % ex)
                pass

        if tpl is None:
            raise TemplateNotFoundError()

        try:
            return self.renderer.render(tpl, data)
        except pystache.common.PystacheError as ex:
            raise TemplatingError(str(ex)) from ex

    def _ensureLoaded(self):
        if self.renderer:
            return

        self.renderer = _WorkaroundRenderer(
                search_dirs=self.app.templates_dirs)


_knowns = ['PieCrustData', 'LazyPageConfigData', 'Paginator', 'Assetor',
           'PageLinkerData']


class _WorkaroundRenderer(pystache.Renderer):
    def _make_resolve_context(self):
        mrc = super(_WorkaroundRenderer, self)._make_resolve_context()

        def _workaround(stack, name):
            # Pystache will treat anything that's not a string or a dict as
            # a list. This is just plain wrong, but it will take a while before
            # the project can get patches on Pypi.
            res = mrc(stack, name)
            if res is not None and (
                    res.__class__.__name__ in _knowns or
                    isinstance(res, collections.abc.Mapping)):
                res = [res]
            return res

        return _workaround