mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-14 02:26:58 -07:00
Initial Commit
This commit is contained in:
commit
88daa3fb91
1311 changed files with 256240 additions and 0 deletions
359
lib/mako/lookup.py
Normal file
359
lib/mako/lookup.py
Normal file
|
@ -0,0 +1,359 @@
|
|||
# mako/lookup.py
|
||||
# Copyright (C) 2006-2015 the Mako authors and contributors <see AUTHORS file>
|
||||
#
|
||||
# This module is part of Mako and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
import os, stat, posixpath, re
|
||||
from mako import exceptions, util
|
||||
from mako.template import Template
|
||||
|
||||
try:
|
||||
import threading
|
||||
except:
|
||||
import dummy_threading as threading
|
||||
|
||||
class TemplateCollection(object):
|
||||
"""Represent a collection of :class:`.Template` objects,
|
||||
identifiable via URI.
|
||||
|
||||
A :class:`.TemplateCollection` is linked to the usage of
|
||||
all template tags that address other templates, such
|
||||
as ``<%include>``, ``<%namespace>``, and ``<%inherit>``.
|
||||
The ``file`` attribute of each of those tags refers
|
||||
to a string URI that is passed to that :class:`.Template`
|
||||
object's :class:`.TemplateCollection` for resolution.
|
||||
|
||||
:class:`.TemplateCollection` is an abstract class,
|
||||
with the usual default implementation being :class:`.TemplateLookup`.
|
||||
|
||||
"""
|
||||
|
||||
def has_template(self, uri):
|
||||
"""Return ``True`` if this :class:`.TemplateLookup` is
|
||||
capable of returning a :class:`.Template` object for the
|
||||
given ``uri``.
|
||||
|
||||
:param uri: String URI of the template to be resolved.
|
||||
|
||||
"""
|
||||
try:
|
||||
self.get_template(uri)
|
||||
return True
|
||||
except exceptions.TemplateLookupException:
|
||||
return False
|
||||
|
||||
def get_template(self, uri, relativeto=None):
|
||||
"""Return a :class:`.Template` object corresponding to the given
|
||||
``uri``.
|
||||
|
||||
The default implementation raises
|
||||
:class:`.NotImplementedError`. Implementations should
|
||||
raise :class:`.TemplateLookupException` if the given ``uri``
|
||||
cannot be resolved.
|
||||
|
||||
:param uri: String URI of the template to be resolved.
|
||||
:param relativeto: if present, the given ``uri`` is assumed to
|
||||
be relative to this URI.
|
||||
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def filename_to_uri(self, uri, filename):
|
||||
"""Convert the given ``filename`` to a URI relative to
|
||||
this :class:`.TemplateCollection`."""
|
||||
|
||||
return uri
|
||||
|
||||
def adjust_uri(self, uri, filename):
|
||||
"""Adjust the given ``uri`` based on the calling ``filename``.
|
||||
|
||||
When this method is called from the runtime, the
|
||||
``filename`` parameter is taken directly to the ``filename``
|
||||
attribute of the calling template. Therefore a custom
|
||||
:class:`.TemplateCollection` subclass can place any string
|
||||
identifier desired in the ``filename`` parameter of the
|
||||
:class:`.Template` objects it constructs and have them come back
|
||||
here.
|
||||
|
||||
"""
|
||||
return uri
|
||||
|
||||
class TemplateLookup(TemplateCollection):
|
||||
"""Represent a collection of templates that locates template source files
|
||||
from the local filesystem.
|
||||
|
||||
The primary argument is the ``directories`` argument, the list of
|
||||
directories to search:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
lookup = TemplateLookup(["/path/to/templates"])
|
||||
some_template = lookup.get_template("/index.html")
|
||||
|
||||
The :class:`.TemplateLookup` can also be given :class:`.Template` objects
|
||||
programatically using :meth:`.put_string` or :meth:`.put_template`:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
lookup = TemplateLookup()
|
||||
lookup.put_string("base.html", '''
|
||||
<html><body>${self.next()}</body></html>
|
||||
''')
|
||||
lookup.put_string("hello.html", '''
|
||||
<%include file='base.html'/>
|
||||
|
||||
Hello, world !
|
||||
''')
|
||||
|
||||
|
||||
:param directories: A list of directory names which will be
|
||||
searched for a particular template URI. The URI is appended
|
||||
to each directory and the filesystem checked.
|
||||
|
||||
:param collection_size: Approximate size of the collection used
|
||||
to store templates. If left at its default of ``-1``, the size
|
||||
is unbounded, and a plain Python dictionary is used to
|
||||
relate URI strings to :class:`.Template` instances.
|
||||
Otherwise, a least-recently-used cache object is used which
|
||||
will maintain the size of the collection approximately to
|
||||
the number given.
|
||||
|
||||
:param filesystem_checks: When at its default value of ``True``,
|
||||
each call to :meth:`.TemplateLookup.get_template()` will
|
||||
compare the filesystem last modified time to the time in
|
||||
which an existing :class:`.Template` object was created.
|
||||
This allows the :class:`.TemplateLookup` to regenerate a
|
||||
new :class:`.Template` whenever the original source has
|
||||
been updated. Set this to ``False`` for a very minor
|
||||
performance increase.
|
||||
|
||||
:param modulename_callable: A callable which, when present,
|
||||
is passed the path of the source file as well as the
|
||||
requested URI, and then returns the full path of the
|
||||
generated Python module file. This is used to inject
|
||||
alternate schemes for Python module location. If left at
|
||||
its default of ``None``, the built in system of generation
|
||||
based on ``module_directory`` plus ``uri`` is used.
|
||||
|
||||
All other keyword parameters available for
|
||||
:class:`.Template` are mirrored here. When new
|
||||
:class:`.Template` objects are created, the keywords
|
||||
established with this :class:`.TemplateLookup` are passed on
|
||||
to each new :class:`.Template`.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
directories=None,
|
||||
module_directory=None,
|
||||
filesystem_checks=True,
|
||||
collection_size=-1,
|
||||
format_exceptions=False,
|
||||
error_handler=None,
|
||||
disable_unicode=False,
|
||||
bytestring_passthrough=False,
|
||||
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):
|
||||
|
||||
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 = {}
|
||||
# transfer deprecated 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,
|
||||
'disable_unicode':disable_unicode,
|
||||
'bytestring_passthrough':bytestring_passthrough,
|
||||
'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):
|
||||
"""Return a :class:`.Template` object corresponding to the given
|
||||
``uri``.
|
||||
|
||||
.. note:: The ``relativeto`` argument is not supported here at the moment.
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
if self.filesystem_checks:
|
||||
return self._check(uri, self._collection[uri])
|
||||
else:
|
||||
return self._collection[uri]
|
||||
except KeyError:
|
||||
u = re.sub(r'^\/+', '', uri)
|
||||
for dir in self.directories:
|
||||
srcfile = posixpath.normpath(posixpath.join(dir, u))
|
||||
if os.path.isfile(srcfile):
|
||||
return self._load(srcfile, uri)
|
||||
else:
|
||||
raise exceptions.TopLevelLookupException(
|
||||
"Cant locate template for uri %r" % uri)
|
||||
|
||||
def adjust_uri(self, uri, relativeto):
|
||||
"""Adjust the given ``uri`` based on the given relative URI."""
|
||||
|
||||
key = (uri, relativeto)
|
||||
if key in self._uri_cache:
|
||||
return self._uri_cache[key]
|
||||
|
||||
if uri[0] != '/':
|
||||
if relativeto is not None:
|
||||
v = self._uri_cache[key] = posixpath.join(
|
||||
posixpath.dirname(relativeto), uri)
|
||||
else:
|
||||
v = self._uri_cache[key] = '/' + uri
|
||||
else:
|
||||
v = self._uri_cache[key] = uri
|
||||
return v
|
||||
|
||||
|
||||
def filename_to_uri(self, filename):
|
||||
"""Convert the given ``filename`` to a URI relative to
|
||||
this :class:`.TemplateCollection`."""
|
||||
|
||||
try:
|
||||
return self._uri_cache[filename]
|
||||
except KeyError:
|
||||
value = self._relativeize(filename)
|
||||
self._uri_cache[filename] = value
|
||||
return value
|
||||
|
||||
def _relativeize(self, filename):
|
||||
"""Return the portion of a filename that is 'relative'
|
||||
to the directories in this lookup.
|
||||
|
||||
"""
|
||||
|
||||
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:
|
||||
# try returning from collection one
|
||||
# more time in case concurrent thread already loaded
|
||||
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:
|
||||
# if compilation fails etc, ensure
|
||||
# template is removed from collection,
|
||||
# re-raise
|
||||
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]:
|
||||
self._collection.pop(uri, None)
|
||||
return self._load(template.filename, uri)
|
||||
else:
|
||||
return template
|
||||
except OSError:
|
||||
self._collection.pop(uri, None)
|
||||
raise exceptions.TemplateLookupException(
|
||||
"Cant locate template for uri %r" % uri)
|
||||
|
||||
|
||||
def put_string(self, uri, text):
|
||||
"""Place a new :class:`.Template` object into this
|
||||
:class:`.TemplateLookup`, based on the given string of
|
||||
``text``.
|
||||
|
||||
"""
|
||||
self._collection[uri] = Template(
|
||||
text,
|
||||
lookup=self,
|
||||
uri=uri,
|
||||
**self.template_args)
|
||||
|
||||
def put_template(self, uri, template):
|
||||
"""Place a new :class:`.Template` object into this
|
||||
:class:`.TemplateLookup`, based on the given
|
||||
:class:`.Template` object.
|
||||
|
||||
"""
|
||||
self._collection[uri] = template
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue