import os
import posixpath
import re
import stat
import threading
from mako import exceptions
from mako import util
from mako.template import Template
class TemplateCollection:
def has_template(self, uri):
try:
self.get_template(uri)
return True
except exceptions.TemplateLookupException:
return False
def get_template(self, uri, relativeto=None):
raise NotImplementedError()
def filename_to_uri(self, uri, filename):
return uri
def adjust_uri(self, uri, filename):
return uri
class TemplateLookup(TemplateCollection):
def __init__(
self,
directories=None,
module_directory=None,
filesystem_checks=True,
collection_size=-1,
format_exceptions=False,
error_handler=None,
output_encoding=None,
encoding_errors="strict",
cache_args=None,
cache_impl="beaker",
cache_enabled=True,
cache_type=None,
cache_dir=None,
cache_url=None,
modulename_callable=None,
module_writer=None,
default_filters=None,
buffer_filters=(),
strict_undefined=False,
imports=None,
future_imports=None,
enable_loop=True,
input_encoding=None,
preprocessor=None,
lexer_cls=None,
include_error_handler=None,
):
self.directories = [
posixpath.normpath(d) for d in util.to_list(directories, ())
]
self.module_directory = module_directory
self.modulename_callable = modulename_callable
self.filesystem_checks = filesystem_checks
self.collection_size = collection_size
if cache_args is None:
cache_args = {}
if cache_dir:
cache_args.setdefault("dir", cache_dir)
if cache_url:
cache_args.setdefault("url", cache_url)
if cache_type:
cache_args.setdefault("type", cache_type)
self.template_args = {
"format_exceptions": format_exceptions,
"error_handler": error_handler,
"include_error_handler": include_error_handler,
"output_encoding": output_encoding,
"cache_impl": cache_impl,
"encoding_errors": encoding_errors,
"input_encoding": input_encoding,
"module_directory": module_directory,
"module_writer": module_writer,
"cache_args": cache_args,
"cache_enabled": cache_enabled,
"default_filters": default_filters,
"buffer_filters": buffer_filters,
"strict_undefined": strict_undefined,
"imports": imports,
"future_imports": future_imports,
"enable_loop": enable_loop,
"preprocessor": preprocessor,
"lexer_cls": lexer_cls,
}
if collection_size == -1:
self._collection = {}
self._uri_cache = {}
else:
self._collection = util.LRUCache(collection_size)
self._uri_cache = util.LRUCache(collection_size)
self._mutex = threading.Lock()
def get_template(self, uri):
try:
if self.filesystem_checks:
return self._check(uri, self._collection[uri])
else:
return self._collection[uri]
except KeyError as e:
u = re.sub(r"^\/+", "", uri)
for dir_ in self.directories:
dir_ = dir_.replace(os.path.sep, posixpath.sep)
srcfile = posixpath.normpath(posixpath.join(dir_, u))
if os.path.isfile(srcfile):
return self._load(srcfile, uri)
else:
raise exceptions.TopLevelLookupException(
"Can't locate template for uri %r" % uri
) from e
def adjust_uri(self, uri, relativeto):
key = (uri, relativeto)
if key in self._uri_cache:
return self._uri_cache[key]
if uri[0] == "/":
v = self._uri_cache[key] = uri
elif relativeto is not None:
v = self._uri_cache[key] = posixpath.join(
posixpath.dirname(relativeto), uri
)
else:
v = self._uri_cache[key] = "/" + uri
return v
def filename_to_uri(self, filename):
try:
return self._uri_cache[filename]
except KeyError:
value = self._relativeize(filename)
self._uri_cache[filename] = value
return value
def _relativeize(self, filename):
filename = posixpath.normpath(filename)
for dir_ in self.directories:
if filename[0 : len(dir_)] == dir_:
return filename[len(dir_) :]
else:
return None
def _load(self, filename, uri):
self._mutex.acquire()
try:
try:
return self._collection[uri]
except KeyError:
pass
try:
if self.modulename_callable is not None:
module_filename = self.modulename_callable(filename, uri)
else:
module_filename = None
self._collection[uri] = template = Template(
uri=uri,
filename=posixpath.normpath(filename),
lookup=self,
module_filename=module_filename,
**self.template_args,
)
return template
except:
self._collection.pop(uri, None)
raise
finally:
self._mutex.release()
def _check(self, uri, template):
if template.filename is None:
return template
try:
template_stat = os.stat(template.filename)
if template.module._modified_time >= template_stat[stat.ST_MTIME]:
return template
self._collection.pop(uri, None)
return self._load(template.filename, uri)
except OSError as e:
self._collection.pop(uri, None)
raise exceptions.TemplateLookupException(
"Can't locate template for uri %r" % uri
) from e
def put_string(self, uri, text):
self._collection[uri] = Template(
text, lookup=self, uri=uri, **self.template_args
)
def put_template(self, uri, template):
self._collection[uri] = template