Index: mojo/public/third_party/jinja2/environment.py |
diff --git a/mojo/public/third_party/jinja2/environment.py b/mojo/public/third_party/jinja2/environment.py |
deleted file mode 100644 |
index 45fabada2eb238504e1c0ccda6e42fd9cf2e707e..0000000000000000000000000000000000000000 |
--- a/mojo/public/third_party/jinja2/environment.py |
+++ /dev/null |
@@ -1,1191 +0,0 @@ |
-# -*- coding: utf-8 -*- |
-""" |
- jinja2.environment |
- ~~~~~~~~~~~~~~~~~~ |
- |
- Provides a class that holds runtime and parsing time options. |
- |
- :copyright: (c) 2010 by the Jinja Team. |
- :license: BSD, see LICENSE for more details. |
-""" |
-import os |
-import sys |
-from jinja2 import nodes |
-from jinja2.defaults import BLOCK_START_STRING, \ |
- BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \ |
- COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \ |
- LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \ |
- DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE, \ |
- KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS |
-from jinja2.lexer import get_lexer, TokenStream |
-from jinja2.parser import Parser |
-from jinja2.nodes import EvalContext |
-from jinja2.optimizer import optimize |
-from jinja2.compiler import generate |
-from jinja2.runtime import Undefined, new_context |
-from jinja2.exceptions import TemplateSyntaxError, TemplateNotFound, \ |
- TemplatesNotFound, TemplateRuntimeError |
-from jinja2.utils import import_string, LRUCache, Markup, missing, \ |
- concat, consume, internalcode |
-from jinja2._compat import imap, ifilter, string_types, iteritems, \ |
- text_type, reraise, implements_iterator, implements_to_string, \ |
- get_next, encode_filename, PY2, PYPY |
-from functools import reduce |
- |
- |
-# for direct template usage we have up to ten living environments |
-_spontaneous_environments = LRUCache(10) |
- |
-# the function to create jinja traceback objects. This is dynamically |
-# imported on the first exception in the exception handler. |
-_make_traceback = None |
- |
- |
-def get_spontaneous_environment(*args): |
- """Return a new spontaneous environment. A spontaneous environment is an |
- unnamed and unaccessible (in theory) environment that is used for |
- templates generated from a string and not from the file system. |
- """ |
- try: |
- env = _spontaneous_environments.get(args) |
- except TypeError: |
- return Environment(*args) |
- if env is not None: |
- return env |
- _spontaneous_environments[args] = env = Environment(*args) |
- env.shared = True |
- return env |
- |
- |
-def create_cache(size): |
- """Return the cache class for the given size.""" |
- if size == 0: |
- return None |
- if size < 0: |
- return {} |
- return LRUCache(size) |
- |
- |
-def copy_cache(cache): |
- """Create an empty copy of the given cache.""" |
- if cache is None: |
- return None |
- elif type(cache) is dict: |
- return {} |
- return LRUCache(cache.capacity) |
- |
- |
-def load_extensions(environment, extensions): |
- """Load the extensions from the list and bind it to the environment. |
- Returns a dict of instantiated environments. |
- """ |
- result = {} |
- for extension in extensions: |
- if isinstance(extension, string_types): |
- extension = import_string(extension) |
- result[extension.identifier] = extension(environment) |
- return result |
- |
- |
-def _environment_sanity_check(environment): |
- """Perform a sanity check on the environment.""" |
- assert issubclass(environment.undefined, Undefined), 'undefined must ' \ |
- 'be a subclass of undefined because filters depend on it.' |
- assert environment.block_start_string != \ |
- environment.variable_start_string != \ |
- environment.comment_start_string, 'block, variable and comment ' \ |
- 'start strings must be different' |
- assert environment.newline_sequence in ('\r', '\r\n', '\n'), \ |
- 'newline_sequence set to unknown line ending string.' |
- return environment |
- |
- |
-class Environment(object): |
- r"""The core component of Jinja is the `Environment`. It contains |
- important shared variables like configuration, filters, tests, |
- globals and others. Instances of this class may be modified if |
- they are not shared and if no template was loaded so far. |
- Modifications on environments after the first template was loaded |
- will lead to surprising effects and undefined behavior. |
- |
- Here the possible initialization parameters: |
- |
- `block_start_string` |
- The string marking the begin of a block. Defaults to ``'{%'``. |
- |
- `block_end_string` |
- The string marking the end of a block. Defaults to ``'%}'``. |
- |
- `variable_start_string` |
- The string marking the begin of a print statement. |
- Defaults to ``'{{'``. |
- |
- `variable_end_string` |
- The string marking the end of a print statement. Defaults to |
- ``'}}'``. |
- |
- `comment_start_string` |
- The string marking the begin of a comment. Defaults to ``'{#'``. |
- |
- `comment_end_string` |
- The string marking the end of a comment. Defaults to ``'#}'``. |
- |
- `line_statement_prefix` |
- If given and a string, this will be used as prefix for line based |
- statements. See also :ref:`line-statements`. |
- |
- `line_comment_prefix` |
- If given and a string, this will be used as prefix for line based |
- based comments. See also :ref:`line-statements`. |
- |
- .. versionadded:: 2.2 |
- |
- `trim_blocks` |
- If this is set to ``True`` the first newline after a block is |
- removed (block, not variable tag!). Defaults to `False`. |
- |
- `lstrip_blocks` |
- If this is set to ``True`` leading spaces and tabs are stripped |
- from the start of a line to a block. Defaults to `False`. |
- |
- `newline_sequence` |
- The sequence that starts a newline. Must be one of ``'\r'``, |
- ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a |
- useful default for Linux and OS X systems as well as web |
- applications. |
- |
- `keep_trailing_newline` |
- Preserve the trailing newline when rendering templates. |
- The default is ``False``, which causes a single newline, |
- if present, to be stripped from the end of the template. |
- |
- .. versionadded:: 2.7 |
- |
- `extensions` |
- List of Jinja extensions to use. This can either be import paths |
- as strings or extension classes. For more information have a |
- look at :ref:`the extensions documentation <jinja-extensions>`. |
- |
- `optimized` |
- should the optimizer be enabled? Default is `True`. |
- |
- `undefined` |
- :class:`Undefined` or a subclass of it that is used to represent |
- undefined values in the template. |
- |
- `finalize` |
- A callable that can be used to process the result of a variable |
- expression before it is output. For example one can convert |
- `None` implicitly into an empty string here. |
- |
- `autoescape` |
- If set to true the XML/HTML autoescaping feature is enabled by |
- default. For more details about auto escaping see |
- :class:`~jinja2.utils.Markup`. As of Jinja 2.4 this can also |
- be a callable that is passed the template name and has to |
- return `True` or `False` depending on autoescape should be |
- enabled by default. |
- |
- .. versionchanged:: 2.4 |
- `autoescape` can now be a function |
- |
- `loader` |
- The template loader for this environment. |
- |
- `cache_size` |
- The size of the cache. Per default this is ``50`` which means |
- that if more than 50 templates are loaded the loader will clean |
- out the least recently used template. If the cache size is set to |
- ``0`` templates are recompiled all the time, if the cache size is |
- ``-1`` the cache will not be cleaned. |
- |
- `auto_reload` |
- Some loaders load templates from locations where the template |
- sources may change (ie: file system or database). If |
- `auto_reload` is set to `True` (default) every time a template is |
- requested the loader checks if the source changed and if yes, it |
- will reload the template. For higher performance it's possible to |
- disable that. |
- |
- `bytecode_cache` |
- If set to a bytecode cache object, this object will provide a |
- cache for the internal Jinja bytecode so that templates don't |
- have to be parsed if they were not changed. |
- |
- See :ref:`bytecode-cache` for more information. |
- """ |
- |
- #: if this environment is sandboxed. Modifying this variable won't make |
- #: the environment sandboxed though. For a real sandboxed environment |
- #: have a look at jinja2.sandbox. This flag alone controls the code |
- #: generation by the compiler. |
- sandboxed = False |
- |
- #: True if the environment is just an overlay |
- overlayed = False |
- |
- #: the environment this environment is linked to if it is an overlay |
- linked_to = None |
- |
- #: shared environments have this set to `True`. A shared environment |
- #: must not be modified |
- shared = False |
- |
- #: these are currently EXPERIMENTAL undocumented features. |
- exception_handler = None |
- exception_formatter = None |
- |
- def __init__(self, |
- block_start_string=BLOCK_START_STRING, |
- block_end_string=BLOCK_END_STRING, |
- variable_start_string=VARIABLE_START_STRING, |
- variable_end_string=VARIABLE_END_STRING, |
- comment_start_string=COMMENT_START_STRING, |
- comment_end_string=COMMENT_END_STRING, |
- line_statement_prefix=LINE_STATEMENT_PREFIX, |
- line_comment_prefix=LINE_COMMENT_PREFIX, |
- trim_blocks=TRIM_BLOCKS, |
- lstrip_blocks=LSTRIP_BLOCKS, |
- newline_sequence=NEWLINE_SEQUENCE, |
- keep_trailing_newline=KEEP_TRAILING_NEWLINE, |
- extensions=(), |
- optimized=True, |
- undefined=Undefined, |
- finalize=None, |
- autoescape=False, |
- loader=None, |
- cache_size=50, |
- auto_reload=True, |
- bytecode_cache=None): |
- # !!Important notice!! |
- # The constructor accepts quite a few arguments that should be |
- # passed by keyword rather than position. However it's important to |
- # not change the order of arguments because it's used at least |
- # internally in those cases: |
- # - spontaneous environments (i18n extension and Template) |
- # - unittests |
- # If parameter changes are required only add parameters at the end |
- # and don't change the arguments (or the defaults!) of the arguments |
- # existing already. |
- |
- # lexer / parser information |
- self.block_start_string = block_start_string |
- self.block_end_string = block_end_string |
- self.variable_start_string = variable_start_string |
- self.variable_end_string = variable_end_string |
- self.comment_start_string = comment_start_string |
- self.comment_end_string = comment_end_string |
- self.line_statement_prefix = line_statement_prefix |
- self.line_comment_prefix = line_comment_prefix |
- self.trim_blocks = trim_blocks |
- self.lstrip_blocks = lstrip_blocks |
- self.newline_sequence = newline_sequence |
- self.keep_trailing_newline = keep_trailing_newline |
- |
- # runtime information |
- self.undefined = undefined |
- self.optimized = optimized |
- self.finalize = finalize |
- self.autoescape = autoescape |
- |
- # defaults |
- self.filters = DEFAULT_FILTERS.copy() |
- self.tests = DEFAULT_TESTS.copy() |
- self.globals = DEFAULT_NAMESPACE.copy() |
- |
- # set the loader provided |
- self.loader = loader |
- self.cache = create_cache(cache_size) |
- self.bytecode_cache = bytecode_cache |
- self.auto_reload = auto_reload |
- |
- # load extensions |
- self.extensions = load_extensions(self, extensions) |
- |
- _environment_sanity_check(self) |
- |
- def add_extension(self, extension): |
- """Adds an extension after the environment was created. |
- |
- .. versionadded:: 2.5 |
- """ |
- self.extensions.update(load_extensions(self, [extension])) |
- |
- def extend(self, **attributes): |
- """Add the items to the instance of the environment if they do not exist |
- yet. This is used by :ref:`extensions <writing-extensions>` to register |
- callbacks and configuration values without breaking inheritance. |
- """ |
- for key, value in iteritems(attributes): |
- if not hasattr(self, key): |
- setattr(self, key, value) |
- |
- def overlay(self, block_start_string=missing, block_end_string=missing, |
- variable_start_string=missing, variable_end_string=missing, |
- comment_start_string=missing, comment_end_string=missing, |
- line_statement_prefix=missing, line_comment_prefix=missing, |
- trim_blocks=missing, lstrip_blocks=missing, |
- extensions=missing, optimized=missing, |
- undefined=missing, finalize=missing, autoescape=missing, |
- loader=missing, cache_size=missing, auto_reload=missing, |
- bytecode_cache=missing): |
- """Create a new overlay environment that shares all the data with the |
- current environment except of cache and the overridden attributes. |
- Extensions cannot be removed for an overlayed environment. An overlayed |
- environment automatically gets all the extensions of the environment it |
- is linked to plus optional extra extensions. |
- |
- Creating overlays should happen after the initial environment was set |
- up completely. Not all attributes are truly linked, some are just |
- copied over so modifications on the original environment may not shine |
- through. |
- """ |
- args = dict(locals()) |
- del args['self'], args['cache_size'], args['extensions'] |
- |
- rv = object.__new__(self.__class__) |
- rv.__dict__.update(self.__dict__) |
- rv.overlayed = True |
- rv.linked_to = self |
- |
- for key, value in iteritems(args): |
- if value is not missing: |
- setattr(rv, key, value) |
- |
- if cache_size is not missing: |
- rv.cache = create_cache(cache_size) |
- else: |
- rv.cache = copy_cache(self.cache) |
- |
- rv.extensions = {} |
- for key, value in iteritems(self.extensions): |
- rv.extensions[key] = value.bind(rv) |
- if extensions is not missing: |
- rv.extensions.update(load_extensions(rv, extensions)) |
- |
- return _environment_sanity_check(rv) |
- |
- lexer = property(get_lexer, doc="The lexer for this environment.") |
- |
- def iter_extensions(self): |
- """Iterates over the extensions by priority.""" |
- return iter(sorted(self.extensions.values(), |
- key=lambda x: x.priority)) |
- |
- def getitem(self, obj, argument): |
- """Get an item or attribute of an object but prefer the item.""" |
- try: |
- return obj[argument] |
- except (TypeError, LookupError): |
- if isinstance(argument, string_types): |
- try: |
- attr = str(argument) |
- except Exception: |
- pass |
- else: |
- try: |
- return getattr(obj, attr) |
- except AttributeError: |
- pass |
- return self.undefined(obj=obj, name=argument) |
- |
- def getattr(self, obj, attribute): |
- """Get an item or attribute of an object but prefer the attribute. |
- Unlike :meth:`getitem` the attribute *must* be a bytestring. |
- """ |
- try: |
- return getattr(obj, attribute) |
- except AttributeError: |
- pass |
- try: |
- return obj[attribute] |
- except (TypeError, LookupError, AttributeError): |
- return self.undefined(obj=obj, name=attribute) |
- |
- def call_filter(self, name, value, args=None, kwargs=None, |
- context=None, eval_ctx=None): |
- """Invokes a filter on a value the same way the compiler does it. |
- |
- .. versionadded:: 2.7 |
- """ |
- func = self.filters.get(name) |
- if func is None: |
- raise TemplateRuntimeError('no filter named %r' % name) |
- args = [value] + list(args or ()) |
- if getattr(func, 'contextfilter', False): |
- if context is None: |
- raise TemplateRuntimeError('Attempted to invoke context ' |
- 'filter without context') |
- args.insert(0, context) |
- elif getattr(func, 'evalcontextfilter', False): |
- if eval_ctx is None: |
- if context is not None: |
- eval_ctx = context.eval_ctx |
- else: |
- eval_ctx = EvalContext(self) |
- args.insert(0, eval_ctx) |
- elif getattr(func, 'environmentfilter', False): |
- args.insert(0, self) |
- return func(*args, **(kwargs or {})) |
- |
- def call_test(self, name, value, args=None, kwargs=None): |
- """Invokes a test on a value the same way the compiler does it. |
- |
- .. versionadded:: 2.7 |
- """ |
- func = self.tests.get(name) |
- if func is None: |
- raise TemplateRuntimeError('no test named %r' % name) |
- return func(value, *(args or ()), **(kwargs or {})) |
- |
- @internalcode |
- def parse(self, source, name=None, filename=None): |
- """Parse the sourcecode and return the abstract syntax tree. This |
- tree of nodes is used by the compiler to convert the template into |
- executable source- or bytecode. This is useful for debugging or to |
- extract information from templates. |
- |
- If you are :ref:`developing Jinja2 extensions <writing-extensions>` |
- this gives you a good overview of the node tree generated. |
- """ |
- try: |
- return self._parse(source, name, filename) |
- except TemplateSyntaxError: |
- exc_info = sys.exc_info() |
- self.handle_exception(exc_info, source_hint=source) |
- |
- def _parse(self, source, name, filename): |
- """Internal parsing function used by `parse` and `compile`.""" |
- return Parser(self, source, name, encode_filename(filename)).parse() |
- |
- def lex(self, source, name=None, filename=None): |
- """Lex the given sourcecode and return a generator that yields |
- tokens as tuples in the form ``(lineno, token_type, value)``. |
- This can be useful for :ref:`extension development <writing-extensions>` |
- and debugging templates. |
- |
- This does not perform preprocessing. If you want the preprocessing |
- of the extensions to be applied you have to filter source through |
- the :meth:`preprocess` method. |
- """ |
- source = text_type(source) |
- try: |
- return self.lexer.tokeniter(source, name, filename) |
- except TemplateSyntaxError: |
- exc_info = sys.exc_info() |
- self.handle_exception(exc_info, source_hint=source) |
- |
- def preprocess(self, source, name=None, filename=None): |
- """Preprocesses the source with all extensions. This is automatically |
- called for all parsing and compiling methods but *not* for :meth:`lex` |
- because there you usually only want the actual source tokenized. |
- """ |
- return reduce(lambda s, e: e.preprocess(s, name, filename), |
- self.iter_extensions(), text_type(source)) |
- |
- def _tokenize(self, source, name, filename=None, state=None): |
- """Called by the parser to do the preprocessing and filtering |
- for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. |
- """ |
- source = self.preprocess(source, name, filename) |
- stream = self.lexer.tokenize(source, name, filename, state) |
- for ext in self.iter_extensions(): |
- stream = ext.filter_stream(stream) |
- if not isinstance(stream, TokenStream): |
- stream = TokenStream(stream, name, filename) |
- return stream |
- |
- def _generate(self, source, name, filename, defer_init=False): |
- """Internal hook that can be overridden to hook a different generate |
- method in. |
- |
- .. versionadded:: 2.5 |
- """ |
- return generate(source, self, name, filename, defer_init=defer_init) |
- |
- def _compile(self, source, filename): |
- """Internal hook that can be overridden to hook a different compile |
- method in. |
- |
- .. versionadded:: 2.5 |
- """ |
- return compile(source, filename, 'exec') |
- |
- @internalcode |
- def compile(self, source, name=None, filename=None, raw=False, |
- defer_init=False): |
- """Compile a node or template source code. The `name` parameter is |
- the load name of the template after it was joined using |
- :meth:`join_path` if necessary, not the filename on the file system. |
- the `filename` parameter is the estimated filename of the template on |
- the file system. If the template came from a database or memory this |
- can be omitted. |
- |
- The return value of this method is a python code object. If the `raw` |
- parameter is `True` the return value will be a string with python |
- code equivalent to the bytecode returned otherwise. This method is |
- mainly used internally. |
- |
- `defer_init` is use internally to aid the module code generator. This |
- causes the generated code to be able to import without the global |
- environment variable to be set. |
- |
- .. versionadded:: 2.4 |
- `defer_init` parameter added. |
- """ |
- source_hint = None |
- try: |
- if isinstance(source, string_types): |
- source_hint = source |
- source = self._parse(source, name, filename) |
- if self.optimized: |
- source = optimize(source, self) |
- source = self._generate(source, name, filename, |
- defer_init=defer_init) |
- if raw: |
- return source |
- if filename is None: |
- filename = '<template>' |
- else: |
- filename = encode_filename(filename) |
- return self._compile(source, filename) |
- except TemplateSyntaxError: |
- exc_info = sys.exc_info() |
- self.handle_exception(exc_info, source_hint=source) |
- |
- def compile_expression(self, source, undefined_to_none=True): |
- """A handy helper method that returns a callable that accepts keyword |
- arguments that appear as variables in the expression. If called it |
- returns the result of the expression. |
- |
- This is useful if applications want to use the same rules as Jinja |
- in template "configuration files" or similar situations. |
- |
- Example usage: |
- |
- >>> env = Environment() |
- >>> expr = env.compile_expression('foo == 42') |
- >>> expr(foo=23) |
- False |
- >>> expr(foo=42) |
- True |
- |
- Per default the return value is converted to `None` if the |
- expression returns an undefined value. This can be changed |
- by setting `undefined_to_none` to `False`. |
- |
- >>> env.compile_expression('var')() is None |
- True |
- >>> env.compile_expression('var', undefined_to_none=False)() |
- Undefined |
- |
- .. versionadded:: 2.1 |
- """ |
- parser = Parser(self, source, state='variable') |
- exc_info = None |
- try: |
- expr = parser.parse_expression() |
- if not parser.stream.eos: |
- raise TemplateSyntaxError('chunk after expression', |
- parser.stream.current.lineno, |
- None, None) |
- expr.set_environment(self) |
- except TemplateSyntaxError: |
- exc_info = sys.exc_info() |
- if exc_info is not None: |
- self.handle_exception(exc_info, source_hint=source) |
- body = [nodes.Assign(nodes.Name('result', 'store'), expr, lineno=1)] |
- template = self.from_string(nodes.Template(body, lineno=1)) |
- return TemplateExpression(template, undefined_to_none) |
- |
- def compile_templates(self, target, extensions=None, filter_func=None, |
- zip='deflated', log_function=None, |
- ignore_errors=True, py_compile=False): |
- """Finds all the templates the loader can find, compiles them |
- and stores them in `target`. If `zip` is `None`, instead of in a |
- zipfile, the templates will be will be stored in a directory. |
- By default a deflate zip algorithm is used, to switch to |
- the stored algorithm, `zip` can be set to ``'stored'``. |
- |
- `extensions` and `filter_func` are passed to :meth:`list_templates`. |
- Each template returned will be compiled to the target folder or |
- zipfile. |
- |
- By default template compilation errors are ignored. In case a |
- log function is provided, errors are logged. If you want template |
- syntax errors to abort the compilation you can set `ignore_errors` |
- to `False` and you will get an exception on syntax errors. |
- |
- If `py_compile` is set to `True` .pyc files will be written to the |
- target instead of standard .py files. This flag does not do anything |
- on pypy and Python 3 where pyc files are not picked up by itself and |
- don't give much benefit. |
- |
- .. versionadded:: 2.4 |
- """ |
- from jinja2.loaders import ModuleLoader |
- |
- if log_function is None: |
- log_function = lambda x: None |
- |
- if py_compile: |
- if not PY2 or PYPY: |
- from warnings import warn |
- warn(Warning('py_compile has no effect on pypy or Python 3')) |
- py_compile = False |
- else: |
- import imp, marshal |
- py_header = imp.get_magic() + \ |
- u'\xff\xff\xff\xff'.encode('iso-8859-15') |
- |
- # Python 3.3 added a source filesize to the header |
- if sys.version_info >= (3, 3): |
- py_header += u'\x00\x00\x00\x00'.encode('iso-8859-15') |
- |
- def write_file(filename, data, mode): |
- if zip: |
- info = ZipInfo(filename) |
- info.external_attr = 0o755 << 16 |
- zip_file.writestr(info, data) |
- else: |
- f = open(os.path.join(target, filename), mode) |
- try: |
- f.write(data) |
- finally: |
- f.close() |
- |
- if zip is not None: |
- from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED |
- zip_file = ZipFile(target, 'w', dict(deflated=ZIP_DEFLATED, |
- stored=ZIP_STORED)[zip]) |
- log_function('Compiling into Zip archive "%s"' % target) |
- else: |
- if not os.path.isdir(target): |
- os.makedirs(target) |
- log_function('Compiling into folder "%s"' % target) |
- |
- try: |
- for name in self.list_templates(extensions, filter_func): |
- source, filename, _ = self.loader.get_source(self, name) |
- try: |
- code = self.compile(source, name, filename, True, True) |
- except TemplateSyntaxError as e: |
- if not ignore_errors: |
- raise |
- log_function('Could not compile "%s": %s' % (name, e)) |
- continue |
- |
- filename = ModuleLoader.get_module_filename(name) |
- |
- if py_compile: |
- c = self._compile(code, encode_filename(filename)) |
- write_file(filename + 'c', py_header + |
- marshal.dumps(c), 'wb') |
- log_function('Byte-compiled "%s" as %s' % |
- (name, filename + 'c')) |
- else: |
- write_file(filename, code, 'w') |
- log_function('Compiled "%s" as %s' % (name, filename)) |
- finally: |
- if zip: |
- zip_file.close() |
- |
- log_function('Finished compiling templates') |
- |
- def list_templates(self, extensions=None, filter_func=None): |
- """Returns a list of templates for this environment. This requires |
- that the loader supports the loader's |
- :meth:`~BaseLoader.list_templates` method. |
- |
- If there are other files in the template folder besides the |
- actual templates, the returned list can be filtered. There are two |
- ways: either `extensions` is set to a list of file extensions for |
- templates, or a `filter_func` can be provided which is a callable that |
- is passed a template name and should return `True` if it should end up |
- in the result list. |
- |
- If the loader does not support that, a :exc:`TypeError` is raised. |
- |
- .. versionadded:: 2.4 |
- """ |
- x = self.loader.list_templates() |
- if extensions is not None: |
- if filter_func is not None: |
- raise TypeError('either extensions or filter_func ' |
- 'can be passed, but not both') |
- filter_func = lambda x: '.' in x and \ |
- x.rsplit('.', 1)[1] in extensions |
- if filter_func is not None: |
- x = ifilter(filter_func, x) |
- return x |
- |
- def handle_exception(self, exc_info=None, rendered=False, source_hint=None): |
- """Exception handling helper. This is used internally to either raise |
- rewritten exceptions or return a rendered traceback for the template. |
- """ |
- global _make_traceback |
- if exc_info is None: |
- exc_info = sys.exc_info() |
- |
- # the debugging module is imported when it's used for the first time. |
- # we're doing a lot of stuff there and for applications that do not |
- # get any exceptions in template rendering there is no need to load |
- # all of that. |
- if _make_traceback is None: |
- from jinja2.debug import make_traceback as _make_traceback |
- traceback = _make_traceback(exc_info, source_hint) |
- if rendered and self.exception_formatter is not None: |
- return self.exception_formatter(traceback) |
- if self.exception_handler is not None: |
- self.exception_handler(traceback) |
- exc_type, exc_value, tb = traceback.standard_exc_info |
- reraise(exc_type, exc_value, tb) |
- |
- def join_path(self, template, parent): |
- """Join a template with the parent. By default all the lookups are |
- relative to the loader root so this method returns the `template` |
- parameter unchanged, but if the paths should be relative to the |
- parent template, this function can be used to calculate the real |
- template name. |
- |
- Subclasses may override this method and implement template path |
- joining here. |
- """ |
- return template |
- |
- @internalcode |
- def _load_template(self, name, globals): |
- if self.loader is None: |
- raise TypeError('no loader for this environment specified') |
- if self.cache is not None: |
- template = self.cache.get(name) |
- if template is not None and (not self.auto_reload or \ |
- template.is_up_to_date): |
- return template |
- template = self.loader.load(self, name, globals) |
- if self.cache is not None: |
- self.cache[name] = template |
- return template |
- |
- @internalcode |
- def get_template(self, name, parent=None, globals=None): |
- """Load a template from the loader. If a loader is configured this |
- method ask the loader for the template and returns a :class:`Template`. |
- If the `parent` parameter is not `None`, :meth:`join_path` is called |
- to get the real template name before loading. |
- |
- The `globals` parameter can be used to provide template wide globals. |
- These variables are available in the context at render time. |
- |
- If the template does not exist a :exc:`TemplateNotFound` exception is |
- raised. |
- |
- .. versionchanged:: 2.4 |
- If `name` is a :class:`Template` object it is returned from the |
- function unchanged. |
- """ |
- if isinstance(name, Template): |
- return name |
- if parent is not None: |
- name = self.join_path(name, parent) |
- return self._load_template(name, self.make_globals(globals)) |
- |
- @internalcode |
- def select_template(self, names, parent=None, globals=None): |
- """Works like :meth:`get_template` but tries a number of templates |
- before it fails. If it cannot find any of the templates, it will |
- raise a :exc:`TemplatesNotFound` exception. |
- |
- .. versionadded:: 2.3 |
- |
- .. versionchanged:: 2.4 |
- If `names` contains a :class:`Template` object it is returned |
- from the function unchanged. |
- """ |
- if not names: |
- raise TemplatesNotFound(message=u'Tried to select from an empty list ' |
- u'of templates.') |
- globals = self.make_globals(globals) |
- for name in names: |
- if isinstance(name, Template): |
- return name |
- if parent is not None: |
- name = self.join_path(name, parent) |
- try: |
- return self._load_template(name, globals) |
- except TemplateNotFound: |
- pass |
- raise TemplatesNotFound(names) |
- |
- @internalcode |
- def get_or_select_template(self, template_name_or_list, |
- parent=None, globals=None): |
- """Does a typecheck and dispatches to :meth:`select_template` |
- if an iterable of template names is given, otherwise to |
- :meth:`get_template`. |
- |
- .. versionadded:: 2.3 |
- """ |
- if isinstance(template_name_or_list, string_types): |
- return self.get_template(template_name_or_list, parent, globals) |
- elif isinstance(template_name_or_list, Template): |
- return template_name_or_list |
- return self.select_template(template_name_or_list, parent, globals) |
- |
- def from_string(self, source, globals=None, template_class=None): |
- """Load a template from a string. This parses the source given and |
- returns a :class:`Template` object. |
- """ |
- globals = self.make_globals(globals) |
- cls = template_class or self.template_class |
- return cls.from_code(self, self.compile(source), globals, None) |
- |
- def make_globals(self, d): |
- """Return a dict for the globals.""" |
- if not d: |
- return self.globals |
- return dict(self.globals, **d) |
- |
- |
-class Template(object): |
- """The central template object. This class represents a compiled template |
- and is used to evaluate it. |
- |
- Normally the template object is generated from an :class:`Environment` but |
- it also has a constructor that makes it possible to create a template |
- instance directly using the constructor. It takes the same arguments as |
- the environment constructor but it's not possible to specify a loader. |
- |
- Every template object has a few methods and members that are guaranteed |
- to exist. However it's important that a template object should be |
- considered immutable. Modifications on the object are not supported. |
- |
- Template objects created from the constructor rather than an environment |
- do have an `environment` attribute that points to a temporary environment |
- that is probably shared with other templates created with the constructor |
- and compatible settings. |
- |
- >>> template = Template('Hello {{ name }}!') |
- >>> template.render(name='John Doe') |
- u'Hello John Doe!' |
- |
- >>> stream = template.stream(name='John Doe') |
- >>> stream.next() |
- u'Hello John Doe!' |
- >>> stream.next() |
- Traceback (most recent call last): |
- ... |
- StopIteration |
- """ |
- |
- def __new__(cls, source, |
- block_start_string=BLOCK_START_STRING, |
- block_end_string=BLOCK_END_STRING, |
- variable_start_string=VARIABLE_START_STRING, |
- variable_end_string=VARIABLE_END_STRING, |
- comment_start_string=COMMENT_START_STRING, |
- comment_end_string=COMMENT_END_STRING, |
- line_statement_prefix=LINE_STATEMENT_PREFIX, |
- line_comment_prefix=LINE_COMMENT_PREFIX, |
- trim_blocks=TRIM_BLOCKS, |
- lstrip_blocks=LSTRIP_BLOCKS, |
- newline_sequence=NEWLINE_SEQUENCE, |
- keep_trailing_newline=KEEP_TRAILING_NEWLINE, |
- extensions=(), |
- optimized=True, |
- undefined=Undefined, |
- finalize=None, |
- autoescape=False): |
- env = get_spontaneous_environment( |
- block_start_string, block_end_string, variable_start_string, |
- variable_end_string, comment_start_string, comment_end_string, |
- line_statement_prefix, line_comment_prefix, trim_blocks, |
- lstrip_blocks, newline_sequence, keep_trailing_newline, |
- frozenset(extensions), optimized, undefined, finalize, autoescape, |
- None, 0, False, None) |
- return env.from_string(source, template_class=cls) |
- |
- @classmethod |
- def from_code(cls, environment, code, globals, uptodate=None): |
- """Creates a template object from compiled code and the globals. This |
- is used by the loaders and environment to create a template object. |
- """ |
- namespace = { |
- 'environment': environment, |
- '__file__': code.co_filename |
- } |
- exec(code, namespace) |
- rv = cls._from_namespace(environment, namespace, globals) |
- rv._uptodate = uptodate |
- return rv |
- |
- @classmethod |
- def from_module_dict(cls, environment, module_dict, globals): |
- """Creates a template object from a module. This is used by the |
- module loader to create a template object. |
- |
- .. versionadded:: 2.4 |
- """ |
- return cls._from_namespace(environment, module_dict, globals) |
- |
- @classmethod |
- def _from_namespace(cls, environment, namespace, globals): |
- t = object.__new__(cls) |
- t.environment = environment |
- t.globals = globals |
- t.name = namespace['name'] |
- t.filename = namespace['__file__'] |
- t.blocks = namespace['blocks'] |
- |
- # render function and module |
- t.root_render_func = namespace['root'] |
- t._module = None |
- |
- # debug and loader helpers |
- t._debug_info = namespace['debug_info'] |
- t._uptodate = None |
- |
- # store the reference |
- namespace['environment'] = environment |
- namespace['__jinja_template__'] = t |
- |
- return t |
- |
- def render(self, *args, **kwargs): |
- """This method accepts the same arguments as the `dict` constructor: |
- A dict, a dict subclass or some keyword arguments. If no arguments |
- are given the context will be empty. These two calls do the same:: |
- |
- template.render(knights='that say nih') |
- template.render({'knights': 'that say nih'}) |
- |
- This will return the rendered template as unicode string. |
- """ |
- vars = dict(*args, **kwargs) |
- try: |
- return concat(self.root_render_func(self.new_context(vars))) |
- except Exception: |
- exc_info = sys.exc_info() |
- return self.environment.handle_exception(exc_info, True) |
- |
- def stream(self, *args, **kwargs): |
- """Works exactly like :meth:`generate` but returns a |
- :class:`TemplateStream`. |
- """ |
- return TemplateStream(self.generate(*args, **kwargs)) |
- |
- def generate(self, *args, **kwargs): |
- """For very large templates it can be useful to not render the whole |
- template at once but evaluate each statement after another and yield |
- piece for piece. This method basically does exactly that and returns |
- a generator that yields one item after another as unicode strings. |
- |
- It accepts the same arguments as :meth:`render`. |
- """ |
- vars = dict(*args, **kwargs) |
- try: |
- for event in self.root_render_func(self.new_context(vars)): |
- yield event |
- except Exception: |
- exc_info = sys.exc_info() |
- else: |
- return |
- yield self.environment.handle_exception(exc_info, True) |
- |
- def new_context(self, vars=None, shared=False, locals=None): |
- """Create a new :class:`Context` for this template. The vars |
- provided will be passed to the template. Per default the globals |
- are added to the context. If shared is set to `True` the data |
- is passed as it to the context without adding the globals. |
- |
- `locals` can be a dict of local variables for internal usage. |
- """ |
- return new_context(self.environment, self.name, self.blocks, |
- vars, shared, self.globals, locals) |
- |
- def make_module(self, vars=None, shared=False, locals=None): |
- """This method works like the :attr:`module` attribute when called |
- without arguments but it will evaluate the template on every call |
- rather than caching it. It's also possible to provide |
- a dict which is then used as context. The arguments are the same |
- as for the :meth:`new_context` method. |
- """ |
- return TemplateModule(self, self.new_context(vars, shared, locals)) |
- |
- @property |
- def module(self): |
- """The template as module. This is used for imports in the |
- template runtime but is also useful if one wants to access |
- exported template variables from the Python layer: |
- |
- >>> t = Template('{% macro foo() %}42{% endmacro %}23') |
- >>> unicode(t.module) |
- u'23' |
- >>> t.module.foo() |
- u'42' |
- """ |
- if self._module is not None: |
- return self._module |
- self._module = rv = self.make_module() |
- return rv |
- |
- def get_corresponding_lineno(self, lineno): |
- """Return the source line number of a line number in the |
- generated bytecode as they are not in sync. |
- """ |
- for template_line, code_line in reversed(self.debug_info): |
- if code_line <= lineno: |
- return template_line |
- return 1 |
- |
- @property |
- def is_up_to_date(self): |
- """If this variable is `False` there is a newer version available.""" |
- if self._uptodate is None: |
- return True |
- return self._uptodate() |
- |
- @property |
- def debug_info(self): |
- """The debug info mapping.""" |
- return [tuple(imap(int, x.split('='))) for x in |
- self._debug_info.split('&')] |
- |
- def __repr__(self): |
- if self.name is None: |
- name = 'memory:%x' % id(self) |
- else: |
- name = repr(self.name) |
- return '<%s %s>' % (self.__class__.__name__, name) |
- |
- |
-@implements_to_string |
-class TemplateModule(object): |
- """Represents an imported template. All the exported names of the |
- template are available as attributes on this object. Additionally |
- converting it into an unicode- or bytestrings renders the contents. |
- """ |
- |
- def __init__(self, template, context): |
- self._body_stream = list(template.root_render_func(context)) |
- self.__dict__.update(context.get_exported()) |
- self.__name__ = template.name |
- |
- def __html__(self): |
- return Markup(concat(self._body_stream)) |
- |
- def __str__(self): |
- return concat(self._body_stream) |
- |
- def __repr__(self): |
- if self.__name__ is None: |
- name = 'memory:%x' % id(self) |
- else: |
- name = repr(self.__name__) |
- return '<%s %s>' % (self.__class__.__name__, name) |
- |
- |
-class TemplateExpression(object): |
- """The :meth:`jinja2.Environment.compile_expression` method returns an |
- instance of this object. It encapsulates the expression-like access |
- to the template with an expression it wraps. |
- """ |
- |
- def __init__(self, template, undefined_to_none): |
- self._template = template |
- self._undefined_to_none = undefined_to_none |
- |
- def __call__(self, *args, **kwargs): |
- context = self._template.new_context(dict(*args, **kwargs)) |
- consume(self._template.root_render_func(context)) |
- rv = context.vars['result'] |
- if self._undefined_to_none and isinstance(rv, Undefined): |
- rv = None |
- return rv |
- |
- |
-@implements_iterator |
-class TemplateStream(object): |
- """A template stream works pretty much like an ordinary python generator |
- but it can buffer multiple items to reduce the number of total iterations. |
- Per default the output is unbuffered which means that for every unbuffered |
- instruction in the template one unicode string is yielded. |
- |
- If buffering is enabled with a buffer size of 5, five items are combined |
- into a new unicode string. This is mainly useful if you are streaming |
- big templates to a client via WSGI which flushes after each iteration. |
- """ |
- |
- def __init__(self, gen): |
- self._gen = gen |
- self.disable_buffering() |
- |
- def dump(self, fp, encoding=None, errors='strict'): |
- """Dump the complete stream into a file or file-like object. |
- Per default unicode strings are written, if you want to encode |
- before writing specify an `encoding`. |
- |
- Example usage:: |
- |
- Template('Hello {{ name }}!').stream(name='foo').dump('hello.html') |
- """ |
- close = False |
- if isinstance(fp, string_types): |
- fp = open(fp, encoding is None and 'w' or 'wb') |
- close = True |
- try: |
- if encoding is not None: |
- iterable = (x.encode(encoding, errors) for x in self) |
- else: |
- iterable = self |
- if hasattr(fp, 'writelines'): |
- fp.writelines(iterable) |
- else: |
- for item in iterable: |
- fp.write(item) |
- finally: |
- if close: |
- fp.close() |
- |
- def disable_buffering(self): |
- """Disable the output buffering.""" |
- self._next = get_next(self._gen) |
- self.buffered = False |
- |
- def enable_buffering(self, size=5): |
- """Enable buffering. Buffer `size` items before yielding them.""" |
- if size <= 1: |
- raise ValueError('buffer size too small') |
- |
- def generator(next): |
- buf = [] |
- c_size = 0 |
- push = buf.append |
- |
- while 1: |
- try: |
- while c_size < size: |
- c = next() |
- push(c) |
- if c: |
- c_size += 1 |
- except StopIteration: |
- if not c_size: |
- return |
- yield concat(buf) |
- del buf[:] |
- c_size = 0 |
- |
- self.buffered = True |
- self._next = get_next(generator(get_next(self._gen))) |
- |
- def __iter__(self): |
- return self |
- |
- def __next__(self): |
- return self._next() |
- |
- |
-# hook in default template class. if anyone reads this comment: ignore that |
-# it's possible to use custom templates ;-) |
-Environment.template_class = Template |