"""
Jinja2 Environment loading helper functions.
Confab uses the environments :meth:`jinja2.Environment.list_templates` method
to abstract template location from rendering and synchronization.
Note that the default Jinja2 Loaders assume a charset (default: utf-8).
"""
from jinja2 import (Environment, FileSystemLoader, PackageLoader, BaseLoader,
StrictUndefined, TemplateNotFound)
from os.path import join, exists
from pkg_resources import get_provider
[docs]class FileSystemEnvironmentLoader(object):
"""Loads Jinja2 environments from directories."""
def __init__(self, dir_name):
self.dir_name = dir_name
def __call__(self, component):
"""
Load a Jinja2 Environment for a component.
"""
component_path = join(self.dir_name, component)
if not exists(component_path):
return Environment(loader=EmptyLoader())
return Environment(loader=ConfabFileSystemLoader(component_path),
undefined=StrictUndefined)
[docs]class PackageEnvironmentLoader(object):
"""Loads Jinja2 environments from python packages."""
def __init__(self, package_name, templates_path='templates'):
self.package_name = package_name
self.templates_path = templates_path
def __call__(self, component):
"""
Load a Jinja2 Environment for a component.
"""
package_path = join(self.templates_path, component)
provider = get_provider(self.package_name)
if not provider.resource_isdir(package_path):
return Environment(loader=EmptyLoader())
return Environment(loader=PackageLoader(self.package_name, package_path),
undefined=StrictUndefined)
[docs]class ConfabFileSystemLoader(FileSystemLoader):
"""Adds support for binary templates when loading an environment from the
file system.
Binary config files cannot be loaded as Jinja2 templates by default, but
since confab's model is built around Jinja2 environments we need to make
sure we can still represent them as Jinja2 Templates.
Since confab only renders templates from text config files (see
:meth:`confab.conffiles.Conffile.generate` and
:meth:`confab.options.should_render`) we can workaround this by returning a
dummy template for binary config files with the appropriate metadata. When
generating the configuration, confab, instead of rendering the template,
will just copy the template file (the binary config file) verbatim to the
generated folder.
"""
def get_source(self, environment, template):
try:
return super(ConfabFileSystemLoader, self).get_source(environment, template)
except UnicodeDecodeError:
pass # not a text file
for searchpath in self.searchpath:
filename = join(searchpath, template)
if exists(filename):
return "", filename, True
raise TemplateNotFound(template)
[docs]class EmptyLoader(BaseLoader):
"""Jinja template loader with no templates."""
def list_templates(self):
return []