summaryrefslogtreecommitdiffstats
path: root/module/lib/jinja2/environment.py
diff options
context:
space:
mode:
authorGravatar Walter Purcaro <vuolter@gmail.com> 2014-07-19 02:01:13 +0200
committerGravatar Walter Purcaro <vuolter@gmail.com> 2014-07-19 02:01:13 +0200
commitac6932aad1e0ccae18fe6332222731502fa119bc (patch)
tree350ceaf26712d4a476e19cfe83cbe14fe4ebb915 /module/lib/jinja2/environment.py
parentFix c1abc13d4dccb20f3845594c28952667573b7d0b (diff)
downloadpyload-ac6932aad1e0ccae18fe6332222731502fa119bc.tar.xz
[Lib] Updated jinja2 to v2.7.3 and markupsafe to v0.23
Diffstat (limited to 'module/lib/jinja2/environment.py')
-rw-r--r--module/lib/jinja2/environment.py175
1 files changed, 124 insertions, 51 deletions
diff --git a/module/lib/jinja2/environment.py b/module/lib/jinja2/environment.py
index ac74a5c68..45fabada2 100644
--- a/module/lib/jinja2/environment.py
+++ b/module/lib/jinja2/environment.py
@@ -11,16 +11,26 @@
import os
import sys
from jinja2 import nodes
-from jinja2.defaults import *
+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
+ TemplatesNotFound, TemplateRuntimeError
from jinja2.utils import import_string, LRUCache, Markup, missing, \
- concat, consume, internalcode, _encode_filename
+ 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
@@ -67,11 +77,11 @@ def copy_cache(cache):
def load_extensions(environment, extensions):
"""Load the extensions from the list and bind it to the environment.
- Returns a dict of instanciated environments.
+ Returns a dict of instantiated environments.
"""
result = {}
for extension in extensions:
- if isinstance(extension, basestring):
+ if isinstance(extension, string_types):
extension = import_string(extension)
result[extension.identifier] = extension(environment)
return result
@@ -134,12 +144,23 @@ class Environment(object):
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
@@ -196,7 +217,8 @@ class Environment(object):
#: 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
+ #: 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
@@ -223,7 +245,9 @@ class Environment(object):
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,
@@ -238,7 +262,7 @@ class Environment(object):
# 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:
- # - spontaneus environments (i18n extension and Template)
+ # - 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
@@ -254,7 +278,9 @@ class Environment(object):
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
@@ -269,7 +295,6 @@ class Environment(object):
# set the loader provided
self.loader = loader
- self.bytecode_cache = None
self.cache = create_cache(cache_size)
self.bytecode_cache = bytecode_cache
self.auto_reload = auto_reload
@@ -291,7 +316,7 @@ class Environment(object):
yet. This is used by :ref:`extensions <writing-extensions>` to register
callbacks and configuration values without breaking inheritance.
"""
- for key, value in attributes.iteritems():
+ for key, value in iteritems(attributes):
if not hasattr(self, key):
setattr(self, key, value)
@@ -299,7 +324,8 @@ class Environment(object):
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, extensions=missing, optimized=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):
@@ -322,7 +348,7 @@ class Environment(object):
rv.overlayed = True
rv.linked_to = self
- for key, value in args.iteritems():
+ for key, value in iteritems(args):
if value is not missing:
setattr(rv, key, value)
@@ -332,7 +358,7 @@ class Environment(object):
rv.cache = copy_cache(self.cache)
rv.extensions = {}
- for key, value in self.extensions.iteritems():
+ 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))
@@ -351,10 +377,10 @@ class Environment(object):
try:
return obj[argument]
except (TypeError, LookupError):
- if isinstance(argument, basestring):
+ if isinstance(argument, string_types):
try:
attr = str(argument)
- except:
+ except Exception:
pass
else:
try:
@@ -376,6 +402,42 @@ class Environment(object):
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
@@ -394,7 +456,7 @@ class Environment(object):
def _parse(self, source, name, filename):
"""Internal parsing function used by `parse` and `compile`."""
- return Parser(self, source, name, _encode_filename(filename)).parse()
+ 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
@@ -406,7 +468,7 @@ class Environment(object):
of the extensions to be applied you have to filter source through
the :meth:`preprocess` method.
"""
- source = unicode(source)
+ source = text_type(source)
try:
return self.lexer.tokeniter(source, name, filename)
except TemplateSyntaxError:
@@ -419,7 +481,7 @@ class Environment(object):
because there you usually only want the actual source tokenized.
"""
return reduce(lambda s, e: e.preprocess(s, name, filename),
- self.iter_extensions(), unicode(source))
+ 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
@@ -434,7 +496,7 @@ class Environment(object):
return stream
def _generate(self, source, name, filename, defer_init=False):
- """Internal hook that can be overriden to hook a different generate
+ """Internal hook that can be overridden to hook a different generate
method in.
.. versionadded:: 2.5
@@ -442,7 +504,7 @@ class Environment(object):
return generate(source, self, name, filename, defer_init=defer_init)
def _compile(self, source, filename):
- """Internal hook that can be overriden to hook a different compile
+ """Internal hook that can be overridden to hook a different compile
method in.
.. versionadded:: 2.5
@@ -473,7 +535,7 @@ class Environment(object):
"""
source_hint = None
try:
- if isinstance(source, basestring):
+ if isinstance(source, string_types):
source_hint = source
source = self._parse(source, name, filename)
if self.optimized:
@@ -485,7 +547,7 @@ class Environment(object):
if filename is None:
filename = '<template>'
else:
- filename = _encode_filename(filename)
+ filename = encode_filename(filename)
return self._compile(source, filename)
except TemplateSyntaxError:
exc_info = sys.exc_info()
@@ -539,7 +601,7 @@ class Environment(object):
def compile_templates(self, target, extensions=None, filter_func=None,
zip='deflated', log_function=None,
ignore_errors=True, py_compile=False):
- """Compiles all the templates the loader can find, compiles them
+ """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
@@ -555,7 +617,9 @@ class Environment(object):
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.
+ 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
"""
@@ -565,14 +629,23 @@ class Environment(object):
log_function = lambda x: None
if py_compile:
- import imp, struct, marshal
- py_header = imp.get_magic() + \
- u'\xff\xff\xff\xff'.encode('iso-8859-15')
+ 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 = 0755 << 16L
+ info.external_attr = 0o755 << 16
zip_file.writestr(info, data)
else:
f = open(os.path.join(target, filename), mode)
@@ -596,7 +669,7 @@ class Environment(object):
source, filename, _ = self.loader.get_source(self, name)
try:
code = self.compile(source, name, filename, True, True)
- except TemplateSyntaxError, e:
+ except TemplateSyntaxError as e:
if not ignore_errors:
raise
log_function('Could not compile "%s": %s' % (name, e))
@@ -605,7 +678,7 @@ class Environment(object):
filename = ModuleLoader.get_module_filename(name)
if py_compile:
- c = self._compile(code, _encode_filename(filename))
+ c = self._compile(code, encode_filename(filename))
write_file(filename + 'c', py_header +
marshal.dumps(c), 'wb')
log_function('Byte-compiled "%s" as %s' %
@@ -632,6 +705,8 @@ class Environment(object):
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:
@@ -641,7 +716,7 @@ class Environment(object):
filter_func = lambda x: '.' in x and \
x.rsplit('.', 1)[1] in extensions
if filter_func is not None:
- x = filter(filter_func, x)
+ x = ifilter(filter_func, x)
return x
def handle_exception(self, exc_info=None, rendered=False, source_hint=None):
@@ -664,7 +739,7 @@ class Environment(object):
if self.exception_handler is not None:
self.exception_handler(traceback)
exc_type, exc_value, tb = traceback.standard_exc_info
- raise exc_type, exc_value, tb
+ reraise(exc_type, exc_value, tb)
def join_path(self, template, parent):
"""Join a template with the parent. By default all the lookups are
@@ -751,7 +826,7 @@ class Environment(object):
.. versionadded:: 2.3
"""
- if isinstance(template_name_or_list, basestring):
+ 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
@@ -813,7 +888,9 @@ class Template(object):
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,
@@ -823,8 +900,9 @@ class Template(object):
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, frozenset(extensions), optimized, undefined,
- finalize, autoescape, None, 0, False, None)
+ 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
@@ -836,7 +914,7 @@ class Template(object):
'environment': environment,
'__file__': code.co_filename
}
- exec code in namespace
+ exec(code, namespace)
rv = cls._from_namespace(environment, namespace, globals)
rv._uptodate = uptodate
return rv
@@ -886,7 +964,7 @@ class Template(object):
vars = dict(*args, **kwargs)
try:
return concat(self.root_render_func(self.new_context(vars)))
- except:
+ except Exception:
exc_info = sys.exc_info()
return self.environment.handle_exception(exc_info, True)
@@ -908,7 +986,7 @@ class Template(object):
try:
for event in self.root_render_func(self.new_context(vars)):
yield event
- except:
+ except Exception:
exc_info = sys.exc_info()
else:
return
@@ -970,7 +1048,7 @@ class Template(object):
@property
def debug_info(self):
"""The debug info mapping."""
- return [tuple(map(int, x.split('='))) for x in
+ return [tuple(imap(int, x.split('='))) for x in
self._debug_info.split('&')]
def __repr__(self):
@@ -981,6 +1059,7 @@ class Template(object):
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
@@ -996,13 +1075,6 @@ class TemplateModule(object):
return Markup(concat(self._body_stream))
def __str__(self):
- return unicode(self).encode('utf-8')
-
- # unicode goes after __str__ because we configured 2to3 to rename
- # __unicode__ to __str__. because the 2to3 tree is not designed to
- # remove nodes from it, we leave the above __str__ around and let
- # it override at runtime.
- def __unicode__(self):
return concat(self._body_stream)
def __repr__(self):
@@ -1032,6 +1104,7 @@ class TemplateExpression(object):
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.
@@ -1050,15 +1123,15 @@ class TemplateStream(object):
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 specifiy an `encoding`.
+ before writing specify an `encoding`.
Example usage::
Template('Hello {{ name }}!').stream(name='foo').dump('hello.html')
"""
close = False
- if isinstance(fp, basestring):
- fp = file(fp, 'w')
+ if isinstance(fp, string_types):
+ fp = open(fp, encoding is None and 'w' or 'wb')
close = True
try:
if encoding is not None:
@@ -1076,7 +1149,7 @@ class TemplateStream(object):
def disable_buffering(self):
"""Disable the output buffering."""
- self._next = self._gen.next
+ self._next = get_next(self._gen)
self.buffered = False
def enable_buffering(self, size=5):
@@ -1104,12 +1177,12 @@ class TemplateStream(object):
c_size = 0
self.buffered = True
- self._next = generator(self._gen.next).next
+ self._next = get_next(generator(get_next(self._gen)))
def __iter__(self):
return self
- def next(self):
+ def __next__(self):
return self._next()