1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
import os
import sys
import threading
from zope.interface import implements
from zope.interface import Interface
from pyramid.asset import resolve_asset_spec
from pyramid.asset import abspath_from_asset_spec
from pyramid.exceptions import ConfigurationError
from pyramid.interfaces import ITemplateRenderer
from pyramid.settings import asbool
from pyramid.util import DottedNameResolver
from mako.lookup import TemplateLookup
from mako import exceptions
class IMakoLookup(Interface):
pass
class PkgResourceTemplateLookup(TemplateLookup):
"""TemplateLookup subclass that handles asset specification URIs"""
def adjust_uri(self, uri, relativeto):
"""Called from within a Mako template, avoids adjusting the
uri if it looks like an asset specification"""
# Don't adjust asset spec names
if ':' in uri:
return uri
return TemplateLookup.adjust_uri(self, uri, relativeto)
def get_template(self, uri):
"""Fetch a template from the cache, or check the filesystem
for it
In addition to the basic filesystem lookup, this subclass will
use pkg_resource to load a file using the asset
specification syntax.
"""
isabs = os.path.isabs(uri)
if (not isabs) and (':' in uri):
try:
if self.filesystem_checks:
return self._check(uri, self._collection[uri])
else:
return self._collection[uri]
except KeyError:
pname, path = resolve_asset_spec(uri)
srcfile = abspath_from_asset_spec(path, pname)
if os.path.isfile(srcfile):
return self._load(srcfile, uri)
raise exceptions.TopLevelLookupException(
"Can not locate template for uri %r" % uri)
return TemplateLookup.get_template(self, uri)
registry_lock = threading.Lock()
def renderer_factory(info):
path = info.name
registry = info.registry
settings = info.settings
lookup = registry.queryUtility(IMakoLookup)
if lookup is None:
reload_templates = settings.get('reload_templates', False)
directories = settings.get('mako.directories', [])
module_directory = settings.get('mako.module_directory', None)
input_encoding = settings.get('mako.input_encoding', 'utf-8')
error_handler = settings.get('mako.error_handler', None)
default_filters = settings.get('mako.default_filters', 'h')
imports = settings.get('mako.imports', None)
strict_undefined = settings.get('mako.strict_undefined', 'false')
preprocessor = settings.get('mako.preprocessor', None)
if not hasattr(directories, '__iter__'):
directories = filter(None, directories.splitlines())
directories = [ abspath_from_asset_spec(d) for d in directories ]
if module_directory is not None:
module_directory = abspath_from_asset_spec(module_directory)
if error_handler is not None:
dotted = DottedNameResolver(info.package)
error_handler = dotted.maybe_resolve(error_handler)
if default_filters is not None:
if not hasattr(default_filters, '__iter__'):
default_filters = filter(None, default_filters.splitlines())
if imports is not None:
if not hasattr(imports, '__iter__'):
imports = filter(None, imports.splitlines())
strict_undefined = asbool(strict_undefined)
if preprocessor is not None:
dotted = DottedNameResolver(info.package)
preprocessor = dotted.maybe_resolve(preprocessor)
lookup = PkgResourceTemplateLookup(directories=directories,
module_directory=module_directory,
input_encoding=input_encoding,
error_handler=error_handler,
default_filters=default_filters,
imports=imports,
filesystem_checks=reload_templates,
strict_undefined=strict_undefined,
preprocessor=preprocessor)
registry_lock.acquire()
try:
registry.registerUtility(lookup, IMakoLookup)
finally:
registry_lock.release()
return MakoLookupTemplateRenderer(path, lookup)
class MakoRenderingException(Exception):
def __init__(self, text):
self.text = text
def __repr__(self):
return self.text
__str__ = __repr__
class MakoLookupTemplateRenderer(object):
implements(ITemplateRenderer)
def __init__(self, path, lookup):
self.path = path
self.lookup = lookup
def implementation(self):
return self.lookup.get_template(self.path)
def __call__(self, value, system):
context = system.pop('context', None)
if context is not None:
system['_context'] = context
def_name = None
if isinstance(value, tuple):
def_name, value = value
try:
system.update(value)
except (TypeError, ValueError):
raise ValueError('renderer was passed non-dictionary as value')
template = self.implementation()
if def_name is not None:
template = template.get_def(def_name)
try:
result = template.render_unicode(**system)
except:
try:
exc_info = sys.exc_info()
errtext = exceptions.text_error_template().render(
error=exc_info[1],
traceback=exc_info[2]
)
raise MakoRenderingException(errtext)
finally:
del exc_info
return result
|