Commit 304fd03e authored by hbristow's avatar hbristow

Updated jinja version

parent 2059972b
...@@ -18,7 +18,7 @@ string(REPLACE "opencv_" "" OPENCV_MATLAB_MODULES "${OPENCV_MODULE_${the_module} ...@@ -18,7 +18,7 @@ string(REPLACE "opencv_" "" OPENCV_MATLAB_MODULES "${OPENCV_MODULE_${the_module}
${OPENCV_MODULE_${the_module}_OPT_DEPS}") ${OPENCV_MODULE_${the_module}_OPT_DEPS}")
foreach(module ${OPENCV_MATLAB_MODULES}) foreach(module ${OPENCV_MATLAB_MODULES})
if (HAVE_opencv_${module}) if (HAVE_opencv_${module})
list(APPEND opencv_hdrs "${OPENCV_MODULE_opencv_${module}_LOCATION}/include/opencv2/${module}/${module}.hpp") list(APPEND opencv_hdrs "${OPENCV_MODULE_opencv_${module}_LOCATION}/include/opencv2/${module}.hpp")
endif() endif()
endforeach() endforeach()
......
...@@ -29,3 +29,5 @@ Patches and suggestions: ...@@ -29,3 +29,5 @@ Patches and suggestions:
- Peter van Dijk (Habbie) - Peter van Dijk (Habbie)
- Stefan Ebner - Stefan Ebner
- Rene Leonhardt - Rene Leonhardt
- Thomas Waldmann
- Cory Benfield (Lukasa)
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
__version__ = '2.7-dev' __version__ = '2.8-dev'
# high level interface # high level interface
from jinja2.environment import Environment, Template from jinja2.environment import Environment, Template
......
# -*- coding: utf-8 -*-
"""
jinja2._compat
~~~~~~~~~~~~~~
Some py2/py3 compatibility support based on a stripped down
version of six so we don't have to depend on a specific version
of it.
:copyright: Copyright 2013 by the Jinja team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import sys
PY2 = sys.version_info[0] == 2
PYPY = hasattr(sys, 'pypy_translation_info')
_identity = lambda x: x
if not PY2:
unichr = chr
range_type = range
text_type = str
string_types = (str,)
iterkeys = lambda d: iter(d.keys())
itervalues = lambda d: iter(d.values())
iteritems = lambda d: iter(d.items())
import pickle
from io import BytesIO, StringIO
NativeStringIO = StringIO
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
ifilter = filter
imap = map
izip = zip
intern = sys.intern
implements_iterator = _identity
implements_to_string = _identity
encode_filename = _identity
get_next = lambda x: x.__next__
else:
unichr = unichr
text_type = unicode
range_type = xrange
string_types = (str, unicode)
iterkeys = lambda d: d.iterkeys()
itervalues = lambda d: d.itervalues()
iteritems = lambda d: d.iteritems()
import cPickle as pickle
from cStringIO import StringIO as BytesIO, StringIO
NativeStringIO = BytesIO
exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
from itertools import imap, izip, ifilter
intern = intern
def implements_iterator(cls):
cls.next = cls.__next__
del cls.__next__
return cls
def implements_to_string(cls):
cls.__unicode__ = cls.__str__
cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
return cls
get_next = lambda x: x.next
def encode_filename(filename):
if isinstance(filename, unicode):
return filename.encode('utf-8')
return filename
def with_metaclass(meta, *bases):
# This requires a bit of explanation: the basic idea is to make a
# dummy metaclass for one level of class instanciation that replaces
# itself with the actual metaclass. Because of internal type checks
# we also need to make sure that we downgrade the custom metaclass
# for one level to something closer to type (that's why __call__ and
# __init__ comes back from type etc.).
#
# This has the advantage over six.with_metaclass in that it does not
# introduce dummy classes into the final MRO.
class metaclass(meta):
__call__ = type.__call__
__init__ = type.__init__
def __new__(cls, name, this_bases, d):
if this_bases is None:
return type.__new__(cls, name, (), d)
return meta(name, bases, d)
return metaclass('temporary_class', None, {})
try:
from urllib.parse import quote_from_bytes as url_quote
except ImportError:
from urllib import quote as url_quote
# -*- coding: utf-8 -*-
"""
jinja2._markupsafe._bundle
~~~~~~~~~~~~~~~~~~~~~~~~~~
This script pulls in markupsafe from a source folder and
bundles it with Jinja2. It does not pull in the speedups
module though.
:copyright: Copyright 2010 by the Jinja team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import sys
import os
import re
def rewrite_imports(lines):
for idx, line in enumerate(lines):
new_line = re.sub(r'(import|from)\s+markupsafe\b',
r'\1 jinja2._markupsafe', line)
if new_line != line:
lines[idx] = new_line
def main():
if len(sys.argv) != 2:
print 'error: only argument is path to markupsafe'
sys.exit(1)
basedir = os.path.dirname(__file__)
markupdir = sys.argv[1]
for filename in os.listdir(markupdir):
if filename.endswith('.py'):
f = open(os.path.join(markupdir, filename))
try:
lines = list(f)
finally:
f.close()
rewrite_imports(lines)
f = open(os.path.join(basedir, filename), 'w')
try:
for line in lines:
f.write(line)
finally:
f.close()
if __name__ == '__main__':
main()
...@@ -18,22 +18,17 @@ from os import path, listdir ...@@ -18,22 +18,17 @@ from os import path, listdir
import sys import sys
import marshal import marshal
import tempfile import tempfile
import cPickle as pickle
import fnmatch import fnmatch
try: from hashlib import sha1
from hashlib import sha1
except ImportError:
from sha import new as sha1
from jinja2.utils import open_if_exists from jinja2.utils import open_if_exists
from jinja2._compat import BytesIO, pickle, PY2
# marshal works better on 3.x, one hack less required # marshal works better on 3.x, one hack less required
if sys.version_info > (3, 0): if not PY2:
from io import BytesIO
marshal_dump = marshal.dump marshal_dump = marshal.dump
marshal_load = marshal.load marshal_load = marshal.load
else: else:
from cStringIO import StringIO as BytesIO
def marshal_dump(code, f): def marshal_dump(code, f):
if isinstance(f, file): if isinstance(f, file):
...@@ -282,15 +277,26 @@ class MemcachedBytecodeCache(BytecodeCache): ...@@ -282,15 +277,26 @@ class MemcachedBytecodeCache(BytecodeCache):
This bytecode cache does not support clearing of used items in the cache. This bytecode cache does not support clearing of used items in the cache.
The clear method is a no-operation function. The clear method is a no-operation function.
.. versionadded:: 2.7
Added support for ignoring memcache errors through the
`ignore_memcache_errors` parameter.
""" """
def __init__(self, client, prefix='jinja2/bytecode/', timeout=None): def __init__(self, client, prefix='jinja2/bytecode/', timeout=None,
ignore_memcache_errors=True):
self.client = client self.client = client
self.prefix = prefix self.prefix = prefix
self.timeout = timeout self.timeout = timeout
self.ignore_memcache_errors = ignore_memcache_errors
def load_bytecode(self, bucket): def load_bytecode(self, bucket):
code = self.client.get(self.prefix + bucket.key) try:
code = self.client.get(self.prefix + bucket.key)
except Exception:
if not self.ignore_memcache_errors:
raise
code = None
if code is not None: if code is not None:
bucket.bytecode_from_string(code) bucket.bytecode_from_string(code)
...@@ -298,4 +304,8 @@ class MemcachedBytecodeCache(BytecodeCache): ...@@ -298,4 +304,8 @@ class MemcachedBytecodeCache(BytecodeCache):
args = (self.prefix + bucket.key, bucket.bytecode_to_string()) args = (self.prefix + bucket.key, bucket.bytecode_to_string())
if self.timeout is not None: if self.timeout is not None:
args += (self.timeout,) args += (self.timeout,)
self.client.set(*args) try:
self.client.set(*args)
except Exception:
if not self.ignore_memcache_errors:
raise
This diff is collapsed.
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
:copyright: (c) 2010 by the Jinja Team. :copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from jinja2._compat import range_type
from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner
...@@ -21,13 +22,15 @@ COMMENT_END_STRING = '#}' ...@@ -21,13 +22,15 @@ COMMENT_END_STRING = '#}'
LINE_STATEMENT_PREFIX = None LINE_STATEMENT_PREFIX = None
LINE_COMMENT_PREFIX = None LINE_COMMENT_PREFIX = None
TRIM_BLOCKS = False TRIM_BLOCKS = False
LSTRIP_BLOCKS = False
NEWLINE_SEQUENCE = '\n' NEWLINE_SEQUENCE = '\n'
KEEP_TRAILING_NEWLINE = False
# default filters, tests and namespace # default filters, tests and namespace
from jinja2.filters import FILTERS as DEFAULT_FILTERS from jinja2.filters import FILTERS as DEFAULT_FILTERS
DEFAULT_NAMESPACE = { DEFAULT_NAMESPACE = {
'range': xrange, 'range': range_type,
'dict': lambda **kw: kw, 'dict': lambda **kw: kw,
'lipsum': generate_lorem_ipsum, 'lipsum': generate_lorem_ipsum,
'cycler': Cycler, 'cycler': Cycler,
......
...@@ -8,24 +8,40 @@ ...@@ -8,24 +8,40 @@
:copyright: (c) 2010 by the Jinja Team. :copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from jinja2._compat import imap, text_type, PY2, implements_to_string
class TemplateError(Exception): class TemplateError(Exception):
"""Baseclass for all template errors.""" """Baseclass for all template errors."""
def __init__(self, message=None): if PY2:
if message is not None: def __init__(self, message=None):
message = unicode(message).encode('utf-8')
Exception.__init__(self, message)
@property
def message(self):
if self.args:
message = self.args[0]
if message is not None: if message is not None:
return message.decode('utf-8', 'replace') message = text_type(message).encode('utf-8')
Exception.__init__(self, message)
@property
def message(self):
if self.args:
message = self.args[0]
if message is not None:
return message.decode('utf-8', 'replace')
def __unicode__(self):
return self.message or u''
else:
def __init__(self, message=None):
Exception.__init__(self, message)
@property
def message(self):
if self.args:
message = self.args[0]
if message is not None:
return message
@implements_to_string
class TemplateNotFound(IOError, LookupError, TemplateError): class TemplateNotFound(IOError, LookupError, TemplateError):
"""Raised if a template does not exist.""" """Raised if a template does not exist."""
...@@ -42,13 +58,6 @@ class TemplateNotFound(IOError, LookupError, TemplateError): ...@@ -42,13 +58,6 @@ class TemplateNotFound(IOError, LookupError, TemplateError):
self.templates = [name] self.templates = [name]
def __str__(self): def __str__(self):
return self.message.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 self.message return self.message
...@@ -63,11 +72,12 @@ class TemplatesNotFound(TemplateNotFound): ...@@ -63,11 +72,12 @@ class TemplatesNotFound(TemplateNotFound):
def __init__(self, names=(), message=None): def __init__(self, names=(), message=None):
if message is None: if message is None:
message = u'none of the templates given were found: ' + \ message = u'none of the templates given were found: ' + \
u', '.join(map(unicode, names)) u', '.join(imap(text_type, names))
TemplateNotFound.__init__(self, names and names[-1] or None, message) TemplateNotFound.__init__(self, names and names[-1] or None, message)
self.templates = list(names) self.templates = list(names)
@implements_to_string
class TemplateSyntaxError(TemplateError): class TemplateSyntaxError(TemplateError):
"""Raised to tell the user that there is a problem with the template.""" """Raised to tell the user that there is a problem with the template."""
...@@ -83,13 +93,6 @@ class TemplateSyntaxError(TemplateError): ...@@ -83,13 +93,6 @@ class TemplateSyntaxError(TemplateError):
self.translated = False self.translated = False
def __str__(self): 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):
# for translated errors we only return the message # for translated errors we only return the message
if self.translated: if self.translated:
return self.message return self.message
......
This diff is collapsed.
...@@ -15,10 +15,13 @@ ...@@ -15,10 +15,13 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import re import re
from operator import itemgetter from operator import itemgetter
from collections import deque from collections import deque
from jinja2.exceptions import TemplateSyntaxError from jinja2.exceptions import TemplateSyntaxError
from jinja2.utils import LRUCache, next from jinja2.utils import LRUCache
from jinja2._compat import iteritems, implements_iterator, text_type, \
intern
# cache for the lexers. Exists in order to be able to have multiple # cache for the lexers. Exists in order to be able to have multiple
...@@ -126,7 +129,7 @@ operators = { ...@@ -126,7 +129,7 @@ operators = {
';': TOKEN_SEMICOLON ';': TOKEN_SEMICOLON
} }
reverse_operators = dict([(v, k) for k, v in operators.iteritems()]) reverse_operators = dict([(v, k) for k, v in iteritems(operators)])
assert len(operators) == len(reverse_operators), 'operators dropped' assert len(operators) == len(reverse_operators), 'operators dropped'
operator_re = re.compile('(%s)' % '|'.join(re.escape(x) for x in operator_re = re.compile('(%s)' % '|'.join(re.escape(x) for x in
sorted(operators, key=lambda x: -len(x)))) sorted(operators, key=lambda x: -len(x))))
...@@ -197,7 +200,7 @@ def compile_rules(environment): ...@@ -197,7 +200,7 @@ def compile_rules(environment):
if environment.line_statement_prefix is not None: if environment.line_statement_prefix is not None:
rules.append((len(environment.line_statement_prefix), 'linestatement', rules.append((len(environment.line_statement_prefix), 'linestatement',
r'^\s*' + e(environment.line_statement_prefix))) r'^[ \t\v]*' + e(environment.line_statement_prefix)))
if environment.line_comment_prefix is not None: if environment.line_comment_prefix is not None:
rules.append((len(environment.line_comment_prefix), 'linecomment', rules.append((len(environment.line_comment_prefix), 'linecomment',
r'(?:^|(?<=\S))[^\S\r\n]*' + r'(?:^|(?<=\S))[^\S\r\n]*' +
...@@ -262,6 +265,7 @@ class Token(tuple): ...@@ -262,6 +265,7 @@ class Token(tuple):
) )
@implements_iterator
class TokenStreamIterator(object): class TokenStreamIterator(object):
"""The iterator for tokenstreams. Iterate over the stream """The iterator for tokenstreams. Iterate over the stream
until the eof token is reached. until the eof token is reached.
...@@ -273,7 +277,7 @@ class TokenStreamIterator(object): ...@@ -273,7 +277,7 @@ class TokenStreamIterator(object):
def __iter__(self): def __iter__(self):
return self return self
def next(self): def __next__(self):
token = self.stream.current token = self.stream.current
if token.type is TOKEN_EOF: if token.type is TOKEN_EOF:
self.stream.close() self.stream.close()
...@@ -282,6 +286,7 @@ class TokenStreamIterator(object): ...@@ -282,6 +286,7 @@ class TokenStreamIterator(object):
return token return token
@implements_iterator
class TokenStream(object): class TokenStream(object):
"""A token stream is an iterable that yields :class:`Token`\s. The """A token stream is an iterable that yields :class:`Token`\s. The
parser however does not iterate over it but calls :meth:`next` to go parser however does not iterate over it but calls :meth:`next` to go
...@@ -289,7 +294,7 @@ class TokenStream(object): ...@@ -289,7 +294,7 @@ class TokenStream(object):
""" """
def __init__(self, generator, name, filename): def __init__(self, generator, name, filename):
self._next = iter(generator).next self._iter = iter(generator)
self._pushed = deque() self._pushed = deque()
self.name = name self.name = name
self.filename = filename self.filename = filename
...@@ -300,8 +305,9 @@ class TokenStream(object): ...@@ -300,8 +305,9 @@ class TokenStream(object):
def __iter__(self): def __iter__(self):
return TokenStreamIterator(self) return TokenStreamIterator(self)
def __nonzero__(self): def __bool__(self):
return bool(self._pushed) or self.current.type is not TOKEN_EOF return bool(self._pushed) or self.current.type is not TOKEN_EOF
__nonzero__ = __bool__ # py2
eos = property(lambda x: not x, doc="Are we at the end of the stream?") eos = property(lambda x: not x, doc="Are we at the end of the stream?")
...@@ -319,7 +325,7 @@ class TokenStream(object): ...@@ -319,7 +325,7 @@ class TokenStream(object):
def skip(self, n=1): def skip(self, n=1):
"""Got n tokens ahead.""" """Got n tokens ahead."""
for x in xrange(n): for x in range(n):
next(self) next(self)
def next_if(self, expr): def next_if(self, expr):
...@@ -333,14 +339,14 @@ class TokenStream(object): ...@@ -333,14 +339,14 @@ class TokenStream(object):
"""Like :meth:`next_if` but only returns `True` or `False`.""" """Like :meth:`next_if` but only returns `True` or `False`."""
return self.next_if(expr) is not None return self.next_if(expr) is not None
def next(self): def __next__(self):
"""Go one token ahead and return the old one""" """Go one token ahead and return the old one"""
rv = self.current rv = self.current
if self._pushed: if self._pushed:
self.current = self._pushed.popleft() self.current = self._pushed.popleft()
elif self.current.type is not TOKEN_EOF: elif self.current.type is not TOKEN_EOF:
try: try:
self.current = self._next() self.current = next(self._iter)
except StopIteration: except StopIteration:
self.close() self.close()
return rv return rv
...@@ -348,7 +354,7 @@ class TokenStream(object): ...@@ -348,7 +354,7 @@ class TokenStream(object):
def close(self): def close(self):
"""Close the stream.""" """Close the stream."""
self.current = Token(self.current.lineno, TOKEN_EOF, '') self.current = Token(self.current.lineno, TOKEN_EOF, '')
self._next = None self._iter = None
self.closed = True self.closed = True
def expect(self, expr): def expect(self, expr):
...@@ -383,7 +389,9 @@ def get_lexer(environment): ...@@ -383,7 +389,9 @@ def get_lexer(environment):
environment.line_statement_prefix, environment.line_statement_prefix,
environment.line_comment_prefix, environment.line_comment_prefix,
environment.trim_blocks, environment.trim_blocks,
environment.newline_sequence) environment.lstrip_blocks,
environment.newline_sequence,
environment.keep_trailing_newline)
lexer = _lexer_cache.get(key) lexer = _lexer_cache.get(key)
if lexer is None: if lexer is None:
lexer = Lexer(environment) lexer = Lexer(environment)
...@@ -425,7 +433,44 @@ class Lexer(object): ...@@ -425,7 +433,44 @@ class Lexer(object):
# block suffix if trimming is enabled # block suffix if trimming is enabled
block_suffix_re = environment.trim_blocks and '\\n?' or '' block_suffix_re = environment.trim_blocks and '\\n?' or ''
# strip leading spaces if lstrip_blocks is enabled
prefix_re = {}
if environment.lstrip_blocks:
# use '{%+' to manually disable lstrip_blocks behavior
no_lstrip_re = e('+')
# detect overlap between block and variable or comment strings
block_diff = c(r'^%s(.*)' % e(environment.block_start_string))
# make sure we don't mistake a block for a variable or a comment
m = block_diff.match(environment.comment_start_string)
no_lstrip_re += m and r'|%s' % e(m.group(1)) or ''
m = block_diff.match(environment.variable_start_string)
no_lstrip_re += m and r'|%s' % e(m.group(1)) or ''
# detect overlap between comment and variable strings
comment_diff = c(r'^%s(.*)' % e(environment.comment_start_string))
m = comment_diff.match(environment.variable_start_string)
no_variable_re = m and r'(?!%s)' % e(m.group(1)) or ''
lstrip_re = r'^[ \t]*'
block_prefix_re = r'%s%s(?!%s)|%s\+?' % (
lstrip_re,
e(environment.block_start_string),
no_lstrip_re,
e(environment.block_start_string),
)
comment_prefix_re = r'%s%s%s|%s\+?' % (
lstrip_re,
e(environment.comment_start_string),
no_variable_re,
e(environment.comment_start_string),
)
prefix_re['block'] = block_prefix_re
prefix_re['comment'] = comment_prefix_re
else:
block_prefix_re = '%s' % e(environment.block_start_string)
self.newline_sequence = environment.newline_sequence self.newline_sequence = environment.newline_sequence
self.keep_trailing_newline = environment.keep_trailing_newline
# global lexing rules # global lexing rules
self.rules = { self.rules = {
...@@ -434,11 +479,11 @@ class Lexer(object): ...@@ -434,11 +479,11 @@ class Lexer(object):
(c('(.*?)(?:%s)' % '|'.join( (c('(.*?)(?:%s)' % '|'.join(
[r'(?P<raw_begin>(?:\s*%s\-|%s)\s*raw\s*(?:\-%s\s*|%s))' % ( [r'(?P<raw_begin>(?:\s*%s\-|%s)\s*raw\s*(?:\-%s\s*|%s))' % (
e(environment.block_start_string), e(environment.block_start_string),
e(environment.block_start_string), block_prefix_re,
e(environment.block_end_string), e(environment.block_end_string),
e(environment.block_end_string) e(environment.block_end_string)
)] + [ )] + [
r'(?P<%s_begin>\s*%s\-|%s)' % (n, r, r) r'(?P<%s_begin>\s*%s\-|%s)' % (n, r, prefix_re.get(n,r))
for n, r in root_tag_rules for n, r in root_tag_rules
])), (TOKEN_DATA, '#bygroup'), '#bygroup'), ])), (TOKEN_DATA, '#bygroup'), '#bygroup'),
# data # data
...@@ -472,7 +517,7 @@ class Lexer(object): ...@@ -472,7 +517,7 @@ class Lexer(object):
TOKEN_RAW_BEGIN: [ TOKEN_RAW_BEGIN: [
(c('(.*?)((?:\s*%s\-|%s)\s*endraw\s*(?:\-%s\s*|%s%s))' % ( (c('(.*?)((?:\s*%s\-|%s)\s*endraw\s*(?:\-%s\s*|%s%s))' % (
e(environment.block_start_string), e(environment.block_start_string),
e(environment.block_start_string), block_prefix_re,
e(environment.block_end_string), e(environment.block_end_string),
e(environment.block_end_string), e(environment.block_end_string),
block_suffix_re block_suffix_re
...@@ -526,7 +571,7 @@ class Lexer(object): ...@@ -526,7 +571,7 @@ class Lexer(object):
value = self._normalize_newlines(value[1:-1]) \ value = self._normalize_newlines(value[1:-1]) \
.encode('ascii', 'backslashreplace') \ .encode('ascii', 'backslashreplace') \
.decode('unicode-escape') .decode('unicode-escape')
except Exception, e: except Exception as e:
msg = str(e).split(':')[-1].strip() msg = str(e).split(':')[-1].strip()
raise TemplateSyntaxError(msg, lineno, name, filename) raise TemplateSyntaxError(msg, lineno, name, filename)
# if we can express it as bytestring (ascii only) # if we can express it as bytestring (ascii only)
...@@ -549,7 +594,14 @@ class Lexer(object): ...@@ -549,7 +594,14 @@ class Lexer(object):
"""This method tokenizes the text and returns the tokens in a """This method tokenizes the text and returns the tokens in a
generator. Use this method if you just want to tokenize a template. generator. Use this method if you just want to tokenize a template.
""" """
source = '\n'.join(unicode(source).splitlines()) source = text_type(source)
lines = source.splitlines()
if self.keep_trailing_newline and source:
for newline in ('\r\n', '\r', '\n'):
if source.endswith(newline):
lines.append('')
break
source = '\n'.join(lines)
pos = 0 pos = 0
lineno = 1 lineno = 1
stack = ['root'] stack = ['root']
...@@ -590,7 +642,7 @@ class Lexer(object): ...@@ -590,7 +642,7 @@ class Lexer(object):
# yield for the current token the first named # yield for the current token the first named
# group that matched # group that matched
elif token == '#bygroup': elif token == '#bygroup':
for key, value in m.groupdict().iteritems(): for key, value in iteritems(m.groupdict()):
if value is not None: if value is not None:
yield lineno, key, value yield lineno, key, value
lineno += value.count('\n') lineno += value.count('\n')
...@@ -647,7 +699,7 @@ class Lexer(object): ...@@ -647,7 +699,7 @@ class Lexer(object):
stack.pop() stack.pop()
# resolve the new state by group checking # resolve the new state by group checking
elif new_state == '#bygroup': elif new_state == '#bygroup':
for key, value in m.groupdict().iteritems(): for key, value in iteritems(m.groupdict()):
if value is not None: if value is not None:
stack.append(key) stack.append(key)
break break
......
...@@ -13,12 +13,10 @@ import sys ...@@ -13,12 +13,10 @@ import sys
import weakref import weakref
from types import ModuleType from types import ModuleType
from os import path from os import path
try: from hashlib import sha1
from hashlib import sha1
except ImportError:
from sha import new as sha1
from jinja2.exceptions import TemplateNotFound from jinja2.exceptions import TemplateNotFound
from jinja2.utils import LRUCache, open_if_exists, internalcode from jinja2.utils import open_if_exists, internalcode
from jinja2._compat import string_types, iteritems
def split_template_path(template): def split_template_path(template):
...@@ -153,7 +151,7 @@ class FileSystemLoader(BaseLoader): ...@@ -153,7 +151,7 @@ class FileSystemLoader(BaseLoader):
""" """
def __init__(self, searchpath, encoding='utf-8'): def __init__(self, searchpath, encoding='utf-8'):
if isinstance(searchpath, basestring): if isinstance(searchpath, string_types):
searchpath = [searchpath] searchpath = [searchpath]
self.searchpath = list(searchpath) self.searchpath = list(searchpath)
self.encoding = encoding self.encoding = encoding
...@@ -274,7 +272,7 @@ class DictLoader(BaseLoader): ...@@ -274,7 +272,7 @@ class DictLoader(BaseLoader):
def get_source(self, environment, template): def get_source(self, environment, template):
if template in self.mapping: if template in self.mapping:
source = self.mapping[template] source = self.mapping[template]
return source, None, lambda: source != self.mapping.get(template) return source, None, lambda: source == self.mapping.get(template)
raise TemplateNotFound(template) raise TemplateNotFound(template)
def list_templates(self): def list_templates(self):
...@@ -306,7 +304,7 @@ class FunctionLoader(BaseLoader): ...@@ -306,7 +304,7 @@ class FunctionLoader(BaseLoader):
rv = self.load_func(template) rv = self.load_func(template)
if rv is None: if rv is None:
raise TemplateNotFound(template) raise TemplateNotFound(template)
elif isinstance(rv, basestring): elif isinstance(rv, string_types):
return rv, None, None return rv, None, None
return rv return rv
...@@ -359,7 +357,7 @@ class PrefixLoader(BaseLoader): ...@@ -359,7 +357,7 @@ class PrefixLoader(BaseLoader):
def list_templates(self): def list_templates(self):
result = [] result = []
for prefix, loader in self.mapping.iteritems(): for prefix, loader in iteritems(self.mapping):
for template in loader.list_templates(): for template in loader.list_templates():
result.append(prefix + self.delimiter + template) result.append(prefix + self.delimiter + template)
return result return result
...@@ -431,7 +429,7 @@ class ModuleLoader(BaseLoader): ...@@ -431,7 +429,7 @@ class ModuleLoader(BaseLoader):
# create a fake module that looks for the templates in the # create a fake module that looks for the templates in the
# path given. # path given.
mod = _TemplateModule(package_name) mod = _TemplateModule(package_name)
if isinstance(path, basestring): if isinstance(path, string_types):
path = [path] path = [path]
else: else:
path = list(path) path = list(path)
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import re import re
from itertools import imap from _compat import text_type, string_types, int_types, \
unichr, PY2
__all__ = ['Markup', 'soft_unicode', 'escape', 'escape_silent'] __all__ = ['Markup', 'soft_unicode', 'escape', 'escape_silent']
...@@ -19,7 +20,7 @@ _striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)') ...@@ -19,7 +20,7 @@ _striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
_entity_re = re.compile(r'&([^;]+);') _entity_re = re.compile(r'&([^;]+);')
class Markup(unicode): class Markup(text_type):
r"""Marks a string as being safe for inclusion in HTML/XML output without r"""Marks a string as being safe for inclusion in HTML/XML output without
needing to be escaped. This implements the `__html__` interface a couple needing to be escaped. This implements the `__html__` interface a couple
of frameworks and web applications use. :class:`Markup` is a direct of frameworks and web applications use. :class:`Markup` is a direct
...@@ -68,65 +69,65 @@ class Markup(unicode): ...@@ -68,65 +69,65 @@ class Markup(unicode):
if hasattr(base, '__html__'): if hasattr(base, '__html__'):
base = base.__html__() base = base.__html__()
if encoding is None: if encoding is None:
return unicode.__new__(cls, base) return text_type.__new__(cls, base)
return unicode.__new__(cls, base, encoding, errors) return text_type.__new__(cls, base, encoding, errors)
def __html__(self): def __html__(self):
return self return self
def __add__(self, other): def __add__(self, other):
if hasattr(other, '__html__') or isinstance(other, basestring): if isinstance(other, string_types) or hasattr(other, '__html__'):
return self.__class__(unicode(self) + unicode(escape(other))) return self.__class__(super(Markup, self).__add__(self.escape(other)))
return NotImplemented return NotImplemented
def __radd__(self, other): def __radd__(self, other):
if hasattr(other, '__html__') or isinstance(other, basestring): if hasattr(other, '__html__') or isinstance(other, string_types):
return self.__class__(unicode(escape(other)) + unicode(self)) return self.escape(other).__add__(self)
return NotImplemented return NotImplemented
def __mul__(self, num): def __mul__(self, num):
if isinstance(num, (int, long)): if isinstance(num, int_types):
return self.__class__(unicode.__mul__(self, num)) return self.__class__(text_type.__mul__(self, num))
return NotImplemented return NotImplemented
__rmul__ = __mul__ __rmul__ = __mul__
def __mod__(self, arg): def __mod__(self, arg):
if isinstance(arg, tuple): if isinstance(arg, tuple):
arg = tuple(imap(_MarkupEscapeHelper, arg)) arg = tuple(_MarkupEscapeHelper(x, self.escape) for x in arg)
else: else:
arg = _MarkupEscapeHelper(arg) arg = _MarkupEscapeHelper(arg, self.escape)
return self.__class__(unicode.__mod__(self, arg)) return self.__class__(text_type.__mod__(self, arg))
def __repr__(self): def __repr__(self):
return '%s(%s)' % ( return '%s(%s)' % (
self.__class__.__name__, self.__class__.__name__,
unicode.__repr__(self) text_type.__repr__(self)
) )
def join(self, seq): def join(self, seq):
return self.__class__(unicode.join(self, imap(escape, seq))) return self.__class__(text_type.join(self, map(self.escape, seq)))
join.__doc__ = unicode.join.__doc__ join.__doc__ = text_type.join.__doc__
def split(self, *args, **kwargs): def split(self, *args, **kwargs):
return map(self.__class__, unicode.split(self, *args, **kwargs)) return list(map(self.__class__, text_type.split(self, *args, **kwargs)))
split.__doc__ = unicode.split.__doc__ split.__doc__ = text_type.split.__doc__
def rsplit(self, *args, **kwargs): def rsplit(self, *args, **kwargs):
return map(self.__class__, unicode.rsplit(self, *args, **kwargs)) return list(map(self.__class__, text_type.rsplit(self, *args, **kwargs)))
rsplit.__doc__ = unicode.rsplit.__doc__ rsplit.__doc__ = text_type.rsplit.__doc__
def splitlines(self, *args, **kwargs): def splitlines(self, *args, **kwargs):
return map(self.__class__, unicode.splitlines(self, *args, **kwargs)) return list(map(self.__class__, text_type.splitlines(self, *args, **kwargs)))
splitlines.__doc__ = unicode.splitlines.__doc__ splitlines.__doc__ = text_type.splitlines.__doc__
def unescape(self): def unescape(self):
r"""Unescape markup again into an unicode string. This also resolves r"""Unescape markup again into an text_type string. This also resolves
known HTML4 and XHTML entities: known HTML4 and XHTML entities:
>>> Markup("Main &raquo; <em>About</em>").unescape() >>> Markup("Main &raquo; <em>About</em>").unescape()
u'Main \xbb <em>About</em>' u'Main \xbb <em>About</em>'
""" """
from jinja2._markupsafe._constants import HTML_ENTITIES from _constants import HTML_ENTITIES
def handle_match(m): def handle_match(m):
name = m.group(1) name = m.group(1)
if name in HTML_ENTITIES: if name in HTML_ENTITIES:
...@@ -139,10 +140,10 @@ class Markup(unicode): ...@@ -139,10 +140,10 @@ class Markup(unicode):
except ValueError: except ValueError:
pass pass
return u'' return u''
return _entity_re.sub(handle_match, unicode(self)) return _entity_re.sub(handle_match, text_type(self))
def striptags(self): def striptags(self):
r"""Unescape markup into an unicode string and strip all tags. This r"""Unescape markup into an text_type string and strip all tags. This
also resolves known HTML4 and XHTML entities. Whitespace is also resolves known HTML4 and XHTML entities. Whitespace is
normalized to one: normalized to one:
...@@ -164,10 +165,10 @@ class Markup(unicode): ...@@ -164,10 +165,10 @@ class Markup(unicode):
return rv return rv
def make_wrapper(name): def make_wrapper(name):
orig = getattr(unicode, name) orig = getattr(text_type, name)
def func(self, *args, **kwargs): def func(self, *args, **kwargs):
args = _escape_argspec(list(args), enumerate(args)) args = _escape_argspec(list(args), enumerate(args), self.escape)
_escape_argspec(kwargs, kwargs.iteritems()) #_escape_argspec(kwargs, kwargs.iteritems(), None)
return self.__class__(orig(self, *args, **kwargs)) return self.__class__(orig(self, *args, **kwargs))
func.__name__ = orig.__name__ func.__name__ = orig.__name__
func.__doc__ = orig.__doc__ func.__doc__ = orig.__doc__
...@@ -180,25 +181,29 @@ class Markup(unicode): ...@@ -180,25 +181,29 @@ class Markup(unicode):
locals()[method] = make_wrapper(method) locals()[method] = make_wrapper(method)
# new in python 2.5 # new in python 2.5
if hasattr(unicode, 'partition'): if hasattr(text_type, 'partition'):
partition = make_wrapper('partition'), def partition(self, sep):
rpartition = make_wrapper('rpartition') return tuple(map(self.__class__,
text_type.partition(self, self.escape(sep))))
def rpartition(self, sep):
return tuple(map(self.__class__,
text_type.rpartition(self, self.escape(sep))))
# new in python 2.6 # new in python 2.6
if hasattr(unicode, 'format'): if hasattr(text_type, 'format'):
format = make_wrapper('format') format = make_wrapper('format')
# not in python 3 # not in python 3
if hasattr(unicode, '__getslice__'): if hasattr(text_type, '__getslice__'):
__getslice__ = make_wrapper('__getslice__') __getslice__ = make_wrapper('__getslice__')
del method, make_wrapper del method, make_wrapper
def _escape_argspec(obj, iterable): def _escape_argspec(obj, iterable, escape):
"""Helper for various string-wrapped functions.""" """Helper for various string-wrapped functions."""
for key, value in iterable: for key, value in iterable:
if hasattr(value, '__html__') or isinstance(value, basestring): if hasattr(value, '__html__') or isinstance(value, string_types):
obj[key] = escape(value) obj[key] = escape(value)
return obj return obj
...@@ -206,13 +211,13 @@ def _escape_argspec(obj, iterable): ...@@ -206,13 +211,13 @@ def _escape_argspec(obj, iterable):
class _MarkupEscapeHelper(object): class _MarkupEscapeHelper(object):
"""Helper for Markup.__mod__""" """Helper for Markup.__mod__"""
def __init__(self, obj): def __init__(self, obj, escape):
self.obj = obj self.obj = obj
self.escape = escape
__getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x]) __getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x], s.escape)
__str__ = lambda s: str(escape(s.obj)) __unicode__ = __str__ = lambda s: text_type(s.escape(s.obj))
__unicode__ = lambda s: unicode(escape(s.obj)) __repr__ = lambda s: str(s.escape(repr(s.obj)))
__repr__ = lambda s: str(escape(repr(s.obj)))
__int__ = lambda s: int(s.obj) __int__ = lambda s: int(s.obj)
__float__ = lambda s: float(s.obj) __float__ = lambda s: float(s.obj)
...@@ -220,6 +225,10 @@ class _MarkupEscapeHelper(object): ...@@ -220,6 +225,10 @@ class _MarkupEscapeHelper(object):
# we have to import it down here as the speedups and native # we have to import it down here as the speedups and native
# modules imports the markup type which is define above. # modules imports the markup type which is define above.
try: try:
from jinja2._markupsafe._speedups import escape, escape_silent, soft_unicode from _speedups import escape, escape_silent, soft_unicode
except ImportError: except ImportError:
from jinja2._markupsafe._native import escape, escape_silent, soft_unicode from _native import escape, escape_silent, soft_unicode
if not PY2:
soft_str = soft_unicode
__all__.append('soft_str')
# -*- coding: utf-8 -*-
"""
markupsafe._compat
~~~~~~~~~~~~~~~~~~
Compatibility module for different Python versions.
:copyright: (c) 2013 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import sys
PY2 = sys.version_info[0] == 2
if not PY2:
text_type = str
string_types = (str,)
unichr = chr
int_types = (int,)
else:
text_type = unicode
string_types = (str, unicode)
unichr = unichr
int_types = (int, long)
# -*- coding: utf-8 -*-
"""
markupsafe._constants
~~~~~~~~~~~~~~~~~~~~~
Highlevel implementation of the Markup string.
:copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
HTML_ENTITIES = {
'AElig': 198,
'Aacute': 193,
'Acirc': 194,
'Agrave': 192,
'Alpha': 913,
'Aring': 197,
'Atilde': 195,
'Auml': 196,
'Beta': 914,
'Ccedil': 199,
'Chi': 935,
'Dagger': 8225,
'Delta': 916,
'ETH': 208,
'Eacute': 201,
'Ecirc': 202,
'Egrave': 200,
'Epsilon': 917,
'Eta': 919,
'Euml': 203,
'Gamma': 915,
'Iacute': 205,
'Icirc': 206,
'Igrave': 204,
'Iota': 921,
'Iuml': 207,
'Kappa': 922,
'Lambda': 923,
'Mu': 924,
'Ntilde': 209,
'Nu': 925,
'OElig': 338,
'Oacute': 211,
'Ocirc': 212,
'Ograve': 210,
'Omega': 937,
'Omicron': 927,
'Oslash': 216,
'Otilde': 213,
'Ouml': 214,
'Phi': 934,
'Pi': 928,
'Prime': 8243,
'Psi': 936,
'Rho': 929,
'Scaron': 352,
'Sigma': 931,
'THORN': 222,
'Tau': 932,
'Theta': 920,
'Uacute': 218,
'Ucirc': 219,
'Ugrave': 217,
'Upsilon': 933,
'Uuml': 220,
'Xi': 926,
'Yacute': 221,
'Yuml': 376,
'Zeta': 918,
'aacute': 225,
'acirc': 226,
'acute': 180,
'aelig': 230,
'agrave': 224,
'alefsym': 8501,
'alpha': 945,
'amp': 38,
'and': 8743,
'ang': 8736,
'apos': 39,
'aring': 229,
'asymp': 8776,
'atilde': 227,
'auml': 228,
'bdquo': 8222,
'beta': 946,
'brvbar': 166,
'bull': 8226,
'cap': 8745,
'ccedil': 231,
'cedil': 184,
'cent': 162,
'chi': 967,
'circ': 710,
'clubs': 9827,
'cong': 8773,
'copy': 169,
'crarr': 8629,
'cup': 8746,
'curren': 164,
'dArr': 8659,
'dagger': 8224,
'darr': 8595,
'deg': 176,
'delta': 948,
'diams': 9830,
'divide': 247,
'eacute': 233,
'ecirc': 234,
'egrave': 232,
'empty': 8709,
'emsp': 8195,
'ensp': 8194,
'epsilon': 949,
'equiv': 8801,
'eta': 951,
'eth': 240,
'euml': 235,
'euro': 8364,
'exist': 8707,
'fnof': 402,
'forall': 8704,
'frac12': 189,
'frac14': 188,
'frac34': 190,
'frasl': 8260,
'gamma': 947,
'ge': 8805,
'gt': 62,
'hArr': 8660,
'harr': 8596,
'hearts': 9829,
'hellip': 8230,
'iacute': 237,
'icirc': 238,
'iexcl': 161,
'igrave': 236,
'image': 8465,
'infin': 8734,
'int': 8747,
'iota': 953,
'iquest': 191,
'isin': 8712,
'iuml': 239,
'kappa': 954,
'lArr': 8656,
'lambda': 955,
'lang': 9001,
'laquo': 171,
'larr': 8592,
'lceil': 8968,
'ldquo': 8220,
'le': 8804,
'lfloor': 8970,
'lowast': 8727,
'loz': 9674,
'lrm': 8206,
'lsaquo': 8249,
'lsquo': 8216,
'lt': 60,
'macr': 175,
'mdash': 8212,
'micro': 181,
'middot': 183,
'minus': 8722,
'mu': 956,
'nabla': 8711,
'nbsp': 160,
'ndash': 8211,
'ne': 8800,
'ni': 8715,
'not': 172,
'notin': 8713,
'nsub': 8836,
'ntilde': 241,
'nu': 957,
'oacute': 243,
'ocirc': 244,
'oelig': 339,
'ograve': 242,
'oline': 8254,
'omega': 969,
'omicron': 959,
'oplus': 8853,
'or': 8744,
'ordf': 170,
'ordm': 186,
'oslash': 248,
'otilde': 245,
'otimes': 8855,
'ouml': 246,
'para': 182,
'part': 8706,
'permil': 8240,
'perp': 8869,
'phi': 966,
'pi': 960,
'piv': 982,
'plusmn': 177,
'pound': 163,
'prime': 8242,
'prod': 8719,
'prop': 8733,
'psi': 968,
'quot': 34,
'rArr': 8658,
'radic': 8730,
'rang': 9002,
'raquo': 187,
'rarr': 8594,
'rceil': 8969,
'rdquo': 8221,
'real': 8476,
'reg': 174,
'rfloor': 8971,
'rho': 961,
'rlm': 8207,
'rsaquo': 8250,
'rsquo': 8217,
'sbquo': 8218,
'scaron': 353,
'sdot': 8901,
'sect': 167,
'shy': 173,
'sigma': 963,
'sigmaf': 962,
'sim': 8764,
'spades': 9824,
'sub': 8834,
'sube': 8838,
'sum': 8721,
'sup': 8835,
'sup1': 185,
'sup2': 178,
'sup3': 179,
'supe': 8839,
'szlig': 223,
'tau': 964,
'there4': 8756,
'theta': 952,
'thetasym': 977,
'thinsp': 8201,
'thorn': 254,
'tilde': 732,
'times': 215,
'trade': 8482,
'uArr': 8657,
'uacute': 250,
'uarr': 8593,
'ucirc': 251,
'ugrave': 249,
'uml': 168,
'upsih': 978,
'upsilon': 965,
'uuml': 252,
'weierp': 8472,
'xi': 958,
'yacute': 253,
'yen': 165,
'yuml': 255,
'zeta': 950,
'zwj': 8205,
'zwnj': 8204
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
:copyright: (c) 2010 by Armin Ronacher. :copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from jinja2._markupsafe import Markup from _compat import text_type
def escape(s): def escape(s):
...@@ -18,7 +18,7 @@ def escape(s): ...@@ -18,7 +18,7 @@ def escape(s):
""" """
if hasattr(s, '__html__'): if hasattr(s, '__html__'):
return s.__html__() return s.__html__()
return Markup(unicode(s) return Markup(text_type(s)
.replace('&', '&amp;') .replace('&', '&amp;')
.replace('>', '&gt;') .replace('>', '&gt;')
.replace('<', '&lt;') .replace('<', '&lt;')
...@@ -40,6 +40,6 @@ def soft_unicode(s): ...@@ -40,6 +40,6 @@ def soft_unicode(s):
"""Make a string unicode if it isn't already. That way a markup """Make a string unicode if it isn't already. That way a markup
string is not converted back to unicode. string is not converted back to unicode.
""" """
if not isinstance(s, unicode): if not isinstance(s, text_type):
s = unicode(s) s = text_type(s)
return s return s
...@@ -12,14 +12,16 @@ ...@@ -12,14 +12,16 @@
:copyright: (c) 2010 by the Jinja Team. :copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import types
import operator import operator
from itertools import chain, izip
from collections import deque from collections import deque
from jinja2.utils import Markup, MethodType, FunctionType from jinja2.utils import Markup
from jinja2._compat import izip, with_metaclass, text_type
#: the types we support for context functions #: the types we support for context functions
_context_function_types = (FunctionType, MethodType) _context_function_types = (types.FunctionType, types.MethodType)
_binop_to_func = { _binop_to_func = {
...@@ -102,9 +104,9 @@ def get_eval_context(node, ctx): ...@@ -102,9 +104,9 @@ def get_eval_context(node, ctx):
return ctx return ctx
class Node(object): class Node(with_metaclass(NodeType, object)):
"""Baseclass for all Jinja2 nodes. There are a number of nodes available """Baseclass for all Jinja2 nodes. There are a number of nodes available
of different types. There are three major types: of different types. There are four major types:
- :class:`Stmt`: statements - :class:`Stmt`: statements
- :class:`Expr`: expressions - :class:`Expr`: expressions
...@@ -118,7 +120,6 @@ class Node(object): ...@@ -118,7 +120,6 @@ class Node(object):
The `environment` attribute is set at the end of the parsing process for The `environment` attribute is set at the end of the parsing process for
all nodes automatically. all nodes automatically.
""" """
__metaclass__ = NodeType
fields = () fields = ()
attributes = ('lineno', 'environment') attributes = ('lineno', 'environment')
abstract = True abstract = True
...@@ -142,7 +143,7 @@ class Node(object): ...@@ -142,7 +143,7 @@ class Node(object):
setattr(self, attr, attributes.pop(attr, None)) setattr(self, attr, attributes.pop(attr, None))
if attributes: if attributes:
raise TypeError('unknown attribute %r' % raise TypeError('unknown attribute %r' %
iter(attributes).next()) next(iter(attributes)))
def iter_fields(self, exclude=None, only=None): def iter_fields(self, exclude=None, only=None):
"""This method iterates over all fields that are defined and yields """This method iterates over all fields that are defined and yields
...@@ -440,7 +441,7 @@ class Const(Literal): ...@@ -440,7 +441,7 @@ class Const(Literal):
constant value in the generated code, otherwise it will raise constant value in the generated code, otherwise it will raise
an `Impossible` exception. an `Impossible` exception.
""" """
from compiler import has_safe_repr from .compiler import has_safe_repr
if not has_safe_repr(value): if not has_safe_repr(value):
raise Impossible() raise Impossible()
return cls(value, lineno=lineno, environment=environment) return cls(value, lineno=lineno, environment=environment)
...@@ -687,7 +688,7 @@ class Concat(Expr): ...@@ -687,7 +688,7 @@ class Concat(Expr):
def as_const(self, eval_ctx=None): def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx) eval_ctx = get_eval_context(self, eval_ctx)
return ''.join(unicode(x.as_const(eval_ctx)) for x in self.nodes) return ''.join(text_type(x.as_const(eval_ctx)) for x in self.nodes)
class Compare(Expr): class Compare(Expr):
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
""" """
from jinja2 import nodes from jinja2 import nodes
from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
from jinja2.utils import next
from jinja2.lexer import describe_token, describe_token_expr from jinja2.lexer import describe_token, describe_token_expr
from jinja2._compat import imap
#: statements that callinto #: statements that callinto
...@@ -53,7 +53,7 @@ class Parser(object): ...@@ -53,7 +53,7 @@ class Parser(object):
def _fail_ut_eof(self, name, end_token_stack, lineno): def _fail_ut_eof(self, name, end_token_stack, lineno):
expected = [] expected = []
for exprs in end_token_stack: for exprs in end_token_stack:
expected.extend(map(describe_token_expr, exprs)) expected.extend(imap(describe_token_expr, exprs))
if end_token_stack: if end_token_stack:
currently_looking = ' or '.join( currently_looking = ' or '.join(
"'%s'" % describe_token_expr(expr) "'%s'" % describe_token_expr(expr)
......
...@@ -8,12 +8,14 @@ ...@@ -8,12 +8,14 @@
:copyright: (c) 2010 by the Jinja Team. :copyright: (c) 2010 by the Jinja Team.
:license: BSD. :license: BSD.
""" """
from itertools import chain, imap from itertools import chain
from jinja2.nodes import EvalContext, _context_function_types from jinja2.nodes import EvalContext, _context_function_types
from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \ from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \
concat, internalcode, next, object_type_repr internalcode, object_type_repr
from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
TemplateNotFound TemplateNotFound
from jinja2._compat import imap, text_type, iteritems, \
implements_iterator, implements_to_string, string_types, PY2
# these variables are exported to the template runtime # these variables are exported to the template runtime
...@@ -23,9 +25,8 @@ __all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup', ...@@ -23,9 +25,8 @@ __all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
'TemplateNotFound'] 'TemplateNotFound']
#: the name of the function that is used to convert something into #: the name of the function that is used to convert something into
#: a string. 2to3 will adopt that automatically and the generated #: a string. We can just use the text type here.
#: code can take advantage of it. to_string = text_type
to_string = unicode
#: the identity function. Useful for certain things in the environment #: the identity function. Useful for certain things in the environment
identity = lambda x: x identity = lambda x: x
...@@ -46,7 +47,7 @@ def markup_join(seq): ...@@ -46,7 +47,7 @@ def markup_join(seq):
def unicode_join(seq): def unicode_join(seq):
"""Simple args to unicode conversion and concatenation.""" """Simple args to unicode conversion and concatenation."""
return concat(imap(unicode, seq)) return concat(imap(text_type, seq))
def new_context(environment, template_name, blocks, vars=None, def new_context(environment, template_name, blocks, vars=None,
...@@ -63,7 +64,7 @@ def new_context(environment, template_name, blocks, vars=None, ...@@ -63,7 +64,7 @@ def new_context(environment, template_name, blocks, vars=None,
# we don't want to modify the dict passed # we don't want to modify the dict passed
if shared: if shared:
parent = dict(parent) parent = dict(parent)
for key, value in locals.iteritems(): for key, value in iteritems(locals):
if key[:2] == 'l_' and value is not missing: if key[:2] == 'l_' and value is not missing:
parent[key[2:]] = value parent[key[2:]] = value
return Context(environment, parent, template_name, blocks) return Context(environment, parent, template_name, blocks)
...@@ -119,7 +120,7 @@ class Context(object): ...@@ -119,7 +120,7 @@ class Context(object):
# create the initial mapping of blocks. Whenever template inheritance # create the initial mapping of blocks. Whenever template inheritance
# takes place the runtime will update this mapping with the new blocks # takes place the runtime will update this mapping with the new blocks
# from the template. # from the template.
self.blocks = dict((k, [v]) for k, v in blocks.iteritems()) self.blocks = dict((k, [v]) for k, v in iteritems(blocks))
def super(self, name, current): def super(self, name, current):
"""Render a parent block.""" """Render a parent block."""
...@@ -171,6 +172,16 @@ class Context(object): ...@@ -171,6 +172,16 @@ class Context(object):
""" """
if __debug__: if __debug__:
__traceback_hide__ = True __traceback_hide__ = True
# Allow callable classes to take a context
fn = __obj.__call__
for fn_type in ('contextfunction',
'evalcontextfunction',
'environmentfunction'):
if hasattr(fn, fn_type):
__obj = fn
break
if isinstance(__obj, _context_function_types): if isinstance(__obj, _context_function_types):
if getattr(__obj, 'contextfunction', 0): if getattr(__obj, 'contextfunction', 0):
args = (__self,) + args args = (__self,) + args
...@@ -191,7 +202,7 @@ class Context(object): ...@@ -191,7 +202,7 @@ class Context(object):
self.parent, True, None, locals) self.parent, True, None, locals)
context.vars.update(self.vars) context.vars.update(self.vars)
context.eval_ctx = self.eval_ctx context.eval_ctx = self.eval_ctx
context.blocks.update((k, list(v)) for k, v in self.blocks.iteritems()) context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks))
return context return context
def _all(meth): def _all(meth):
...@@ -205,7 +216,7 @@ class Context(object): ...@@ -205,7 +216,7 @@ class Context(object):
items = _all('items') items = _all('items')
# not available on python 3 # not available on python 3
if hasattr(dict, 'iterkeys'): if PY2:
iterkeys = _all('iterkeys') iterkeys = _all('iterkeys')
itervalues = _all('itervalues') itervalues = _all('itervalues')
iteritems = _all('iteritems') iteritems = _all('iteritems')
...@@ -269,11 +280,12 @@ class BlockReference(object): ...@@ -269,11 +280,12 @@ class BlockReference(object):
class LoopContext(object): class LoopContext(object):
"""A loop context for dynamic iteration.""" """A loop context for dynamic iteration."""
def __init__(self, iterable, recurse=None): def __init__(self, iterable, recurse=None, depth0=0):
self._iterator = iter(iterable) self._iterator = iter(iterable)
self._recurse = recurse self._recurse = recurse
self._after = self._safe_next() self._after = self._safe_next()
self.index0 = -1 self.index0 = -1
self.depth0 = depth0
# try to get the length of the iterable early. This must be done # try to get the length of the iterable early. This must be done
# here because there are some broken iterators around where there # here because there are some broken iterators around where there
...@@ -295,6 +307,7 @@ class LoopContext(object): ...@@ -295,6 +307,7 @@ class LoopContext(object):
index = property(lambda x: x.index0 + 1) index = property(lambda x: x.index0 + 1)
revindex = property(lambda x: x.length - x.index0) revindex = property(lambda x: x.length - x.index0)
revindex0 = property(lambda x: x.length - x.index) revindex0 = property(lambda x: x.length - x.index)
depth = property(lambda x: x.depth0 + 1)
def __len__(self): def __len__(self):
return self.length return self.length
...@@ -313,7 +326,7 @@ class LoopContext(object): ...@@ -313,7 +326,7 @@ class LoopContext(object):
if self._recurse is None: if self._recurse is None:
raise TypeError('Tried to call non recursive loop. Maybe you ' raise TypeError('Tried to call non recursive loop. Maybe you '
"forgot the 'recursive' modifier.") "forgot the 'recursive' modifier.")
return self._recurse(iterable, self._recurse) return self._recurse(iterable, self._recurse, self.depth0 + 1)
# a nifty trick to enhance the error message if someone tried to call # a nifty trick to enhance the error message if someone tried to call
# the the loop without or with too many arguments. # the the loop without or with too many arguments.
...@@ -340,6 +353,7 @@ class LoopContext(object): ...@@ -340,6 +353,7 @@ class LoopContext(object):
) )
@implements_iterator
class LoopContextIterator(object): class LoopContextIterator(object):
"""The iterator for a loop context.""" """The iterator for a loop context."""
__slots__ = ('context',) __slots__ = ('context',)
...@@ -350,7 +364,7 @@ class LoopContextIterator(object): ...@@ -350,7 +364,7 @@ class LoopContextIterator(object):
def __iter__(self): def __iter__(self):
return self return self
def next(self): def __next__(self):
ctx = self.context ctx = self.context
ctx.index0 += 1 ctx.index0 += 1
if ctx._after is _last_iteration: if ctx._after is _last_iteration:
...@@ -424,6 +438,7 @@ class Macro(object): ...@@ -424,6 +438,7 @@ class Macro(object):
) )
@implements_to_string
class Undefined(object): class Undefined(object):
"""The default undefined type. This undefined type can be printed and """The default undefined type. This undefined type can be printed and
iterated over, but every other access will raise an :exc:`UndefinedError`: iterated over, but every other access will raise an :exc:`UndefinedError`:
...@@ -455,7 +470,7 @@ class Undefined(object): ...@@ -455,7 +470,7 @@ class Undefined(object):
if self._undefined_hint is None: if self._undefined_hint is None:
if self._undefined_obj is missing: if self._undefined_obj is missing:
hint = '%r is undefined' % self._undefined_name hint = '%r is undefined' % self._undefined_name
elif not isinstance(self._undefined_name, basestring): elif not isinstance(self._undefined_name, string_types):
hint = '%s has no element %r' % ( hint = '%s has no element %r' % (
object_type_repr(self._undefined_obj), object_type_repr(self._undefined_obj),
self._undefined_name self._undefined_name
...@@ -483,13 +498,6 @@ class Undefined(object): ...@@ -483,13 +498,6 @@ class Undefined(object):
_fail_with_undefined_error _fail_with_undefined_error
def __str__(self): 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 u'' return u''
def __len__(self): def __len__(self):
...@@ -506,6 +514,7 @@ class Undefined(object): ...@@ -506,6 +514,7 @@ class Undefined(object):
return 'Undefined' return 'Undefined'
@implements_to_string
class DebugUndefined(Undefined): class DebugUndefined(Undefined):
"""An undefined that returns the debug info when printed. """An undefined that returns the debug info when printed.
...@@ -521,7 +530,7 @@ class DebugUndefined(Undefined): ...@@ -521,7 +530,7 @@ class DebugUndefined(Undefined):
""" """
__slots__ = () __slots__ = ()
def __unicode__(self): def __str__(self):
if self._undefined_hint is None: if self._undefined_hint is None:
if self._undefined_obj is missing: if self._undefined_obj is missing:
return u'{{ %s }}' % self._undefined_name return u'{{ %s }}' % self._undefined_name
...@@ -532,6 +541,7 @@ class DebugUndefined(Undefined): ...@@ -532,6 +541,7 @@ class DebugUndefined(Undefined):
return u'{{ undefined value printed: %s }}' % self._undefined_hint return u'{{ undefined value printed: %s }}' % self._undefined_hint
@implements_to_string
class StrictUndefined(Undefined): class StrictUndefined(Undefined):
"""An undefined that barks on print and iteration as well as boolean """An undefined that barks on print and iteration as well as boolean
tests and all kinds of comparisons. In other words: you can do nothing tests and all kinds of comparisons. In other words: you can do nothing
...@@ -552,7 +562,7 @@ class StrictUndefined(Undefined): ...@@ -552,7 +562,7 @@ class StrictUndefined(Undefined):
UndefinedError: 'foo' is undefined UndefinedError: 'foo' is undefined
""" """
__slots__ = () __slots__ = ()
__iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \ __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \
__ne__ = __bool__ = Undefined._fail_with_undefined_error __ne__ = __bool__ = Undefined._fail_with_undefined_error
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment