Source code for ducktape.template

# Copyright 2015 Confluent Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from ducktape.utils.util import package_is_installed

from jinja2 import Template, FileSystemLoader, PackageLoader, ChoiceLoader, Environment
import os.path
import inspect


[docs]class TemplateRenderer(object): def _get_ctx(self): ctx = {k: getattr(self.__class__, k) for k in dir(self.__class__)} ctx.update(self.__dict__) return ctx
[docs] def render_template(self, template, **kwargs): """ Render a template using the context of the current object, optionally with overrides. :param template: the template to render, a Template or a str :param kwargs: optional override parameters :return: the rendered template """ if not hasattr(template, 'render'): template = Template(template) ctx = self._get_ctx() return template.render(ctx, **kwargs)
@staticmethod def _package_search_path(module_name): """ :param module_name: Name of a module :return: (package, package_search_path) where package is the package containing the module, and package_search_path is a path relative to the package in which to search for templates. """ module_parts = module_name.split(".") package = module_parts[0] # Construct path relative to package under which "templates" would be found directory = "" for d in module_parts[1: -1]: directory = os.path.join(directory, d) return package, os.path.join(directory, "templates")
[docs] def render(self, path, **kwargs): """ Render a template loaded from a file. template files referenced in file f should be in a sibling directory of f called "templates". :param path: path, relative to the search paths, to the template file :param kwargs: optional override parameters :return: the rendered template """ if not hasattr(self, 'template_loader'): class_dir = os.path.dirname(inspect.getfile(self.__class__)) module_name = self.__class__.__module__ package, package_search_path = self._package_search_path(module_name) loaders = [] msg = "" if os.path.isdir(class_dir): # FileSystemLoader overrides PackageLoader if the path containing this directory # is a valid directory. FileSystemLoader throws an error from which ChoiceLoader # doesn't recover if the directory is invalid loaders.append(FileSystemLoader(os.path.join(class_dir, 'templates'))) else: msg += "Will not search in %s for template files since it is not a valid directory. " % class_dir if package_is_installed(package): loaders.append(PackageLoader(package, package_search_path)) else: msg += "Will not search in package %s for template files because it cannot be imported." if len(loaders) == 0: # Expect at least one of FileSystemLoader and PackageLoader to be present raise EnvironmentError(msg) self.template_loader = ChoiceLoader(loaders) self.template_env = Environment(loader=self.template_loader, trim_blocks=True, lstrip_blocks=True) template = self.template_env.get_template(path) return self.render_template(template, **kwargs)