blob: 793dde10ad61717e8eacee32d90333186dd048ee [file] [log] [blame]
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import mako.lookup
import mako.template
class MakoRenderer(object):
"""Represents a renderer object implemented with Mako templates."""
def __init__(self, template_dirs=None):
template_dirs = template_dirs or []
self._template_lookup = mako.lookup.TemplateLookup(
directories=template_dirs)
self._caller_stack = []
def render(self,
caller,
template_path=None,
template_text=None,
template_vars=None):
"""
Renders the template with variable bindings.
It's okay to invoke |render| method recursively and |caller| is pushed
onto the call stack, which is accessible via |callers| and |last_caller|
methods.
Args:
template_path: A filepath to a template file.
template_text: A text content to be used as a template. Either of
|template_path| or |template_text| must be specified.
template_vars: Template variable bindings.
caller: An object to be pushed onto the call stack.
"""
assert not (template_path is None and template_text is None)
assert not (template_path and template_text)
assert isinstance(template_vars, dict)
assert caller is not None
self._caller_stack.append(caller)
try:
if template_path:
template = self._template_lookup.get_template(template_path)
elif template_text:
template = mako.template.Template(text=template_text)
text = template.render(**template_vars)
finally:
self._caller_stack.pop()
return text
@property
def callers(self):
"""
Returns the callers of this renderer in the order from the last caller
to the first caller.
"""
return reversed(self._caller_stack)
@property
def last_caller(self):
"""Returns the last caller in the call stack of this renderer."""
return self._caller_stack[-1]