]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
python 3 port: manual fixes, remove 2to3 from setup.py, remove fixers
authorThomas Waldmann <tw@waldmann-edv.de>
Fri, 17 May 2013 22:06:22 +0000 (00:06 +0200)
committerThomas Waldmann <tw@waldmann-edv.de>
Fri, 17 May 2013 22:06:22 +0000 (00:06 +0200)
28 files changed:
custom_fixers/__init__.py [deleted file]
custom_fixers/fix_alt_unicode.py [deleted file]
custom_fixers/fix_broken_reraising.py [deleted file]
custom_fixers/fix_xrange2.py [deleted file]
jinja2/_markupsafe/__init__.py
jinja2/_markupsafe/_native.py
jinja2/bccache.py
jinja2/compiler.py
jinja2/debug.py
jinja2/defaults.py
jinja2/environment.py
jinja2/exceptions.py
jinja2/ext.py
jinja2/filters.py
jinja2/lexer.py
jinja2/loaders.py
jinja2/meta.py
jinja2/nodes.py
jinja2/parser.py
jinja2/runtime.py
jinja2/sandbox.py
jinja2/tests.py
jinja2/testsuite/ext.py
jinja2/testsuite/filters.py
jinja2/testsuite/lexnparse.py
jinja2/testsuite/regression.py
jinja2/utils.py
setup.py

diff --git a/custom_fixers/__init__.py b/custom_fixers/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/custom_fixers/fix_alt_unicode.py b/custom_fixers/fix_alt_unicode.py
deleted file mode 100644 (file)
index 96a81c1..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from lib2to3 import fixer_base
-from lib2to3.fixer_util import Name, BlankLine
-
-
-class FixAltUnicode(fixer_base.BaseFix):
-    PATTERN = """
-    func=funcdef< 'def' name='__unicode__'
-                  parameters< '(' NAME ')' > any+ >
-    """
-
-    def transform(self, node, results):
-        name = results['name']
-        name.replace(Name('__str__', prefix=name.prefix))
diff --git a/custom_fixers/fix_broken_reraising.py b/custom_fixers/fix_broken_reraising.py
deleted file mode 100644 (file)
index fd0ea68..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-from lib2to3 import fixer_base, pytree
-from lib2to3.fixer_util import Name, BlankLine, Name, Attr, ArgList
-
-
-class FixBrokenReraising(fixer_base.BaseFix):
-    PATTERN = """
-    raise_stmt< 'raise' any ',' val=any ',' tb=any >
-    """
-
-    # run before the broken 2to3 checker with the same goal
-    # tries to rewrite it with a rule that does not work out for jinja
-    run_order = 1
-
-    def transform(self, node, results):
-        tb = results['tb'].clone()
-        tb.prefix = ''
-        with_tb = Attr(results['val'].clone(), Name('with_traceback')) + \
-                  [ArgList([tb])]
-        new = pytree.Node(self.syms.simple_stmt, [Name("raise")] + with_tb)
-        new.prefix = node.prefix
-        return new
diff --git a/custom_fixers/fix_xrange2.py b/custom_fixers/fix_xrange2.py
deleted file mode 100644 (file)
index 5d35e50..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-from lib2to3 import fixer_base
-from lib2to3.fixer_util import Name, BlankLine
-
-
-# whyever this is necessary..
-
-class FixXrange2(fixer_base.BaseFix):
-    PATTERN = "'xrange'"
-
-    def transform(self, node, results):
-        node.replace(Name('range', prefix=node.prefix))
index 6aae11a4ca048c5438a12ef32fbf11cc4f35fa09..a353ff3e8f04afc3246b2dd90da009c7ef2fbb9b 100644 (file)
@@ -9,11 +9,13 @@
     :license: BSD, see LICENSE for more details.
 """
 import re
-from itertools import imap
 import six
 from six.moves import map
 from six.moves import zip
-
+try:
+    unichr = unichr  # py2
+except NameError:
+    unichr = chr  # py3
 
 __all__ = ['Markup', 'soft_unicode', 'escape', 'escape_silent']
 
@@ -22,7 +24,7 @@ _striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
 _entity_re = re.compile(r'&([^;]+);')
 
 
-class Markup(unicode):
+class Markup(six.text_type):
     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
     of frameworks and web applications use.  :class:`Markup` is a direct
@@ -71,56 +73,56 @@ class Markup(unicode):
         if hasattr(base, '__html__'):
             base = base.__html__()
         if encoding is None:
-            return unicode.__new__(cls, base)
-        return unicode.__new__(cls, base, encoding, errors)
+            return six.text_type.__new__(cls, base)
+        return six.text_type.__new__(cls, base, encoding, errors)
 
     def __html__(self):
         return self
 
     def __add__(self, other):
-        if hasattr(other, '__html__') or isinstance(other, basestring):
+        if hasattr(other, '__html__') or isinstance(other, six.string_types):
             return self.__class__(six.text_type(self) + six.text_type(escape(other)))
         return NotImplemented
 
     def __radd__(self, other):
-        if hasattr(other, '__html__') or isinstance(other, basestring):
+        if hasattr(other, '__html__') or isinstance(other, six.string_types):
             return self.__class__(six.text_type(escape(other)) + six.text_type(self))
         return NotImplemented
 
     def __mul__(self, num):
         if isinstance(num, (int, long)):
-            return self.__class__(unicode.__mul__(self, num))
+            return self.__class__(six.text_type.__mul__(self, num))
         return NotImplemented
     __rmul__ = __mul__
 
     def __mod__(self, arg):
         if isinstance(arg, tuple):
-            arg = tuple(imap(_MarkupEscapeHelper, arg))
+            arg = tuple(map(_MarkupEscapeHelper, arg))
         else:
             arg = _MarkupEscapeHelper(arg)
-        return self.__class__(unicode.__mod__(self, arg))
+        return self.__class__(six.text_type.__mod__(self, arg))
 
     def __repr__(self):
         return '%s(%s)' % (
             self.__class__.__name__,
-            unicode.__repr__(self)
+            six.text_type.__repr__(self)
         )
 
     def join(self, seq):
-        return self.__class__(unicode.join(self, imap(escape, seq)))
-    join.__doc__ = unicode.join.__doc__
+        return self.__class__(six.text_type.join(self, map(escape, seq)))
+    join.__doc__ = six.text_type.join.__doc__
 
     def split(self, *args, **kwargs):
-        return map(self.__class__, unicode.split(self, *args, **kwargs))
-    split.__doc__ = unicode.split.__doc__
+        return map(self.__class__, six.text_type.split(self, *args, **kwargs))
+    split.__doc__ = six.text_type.split.__doc__
 
     def rsplit(self, *args, **kwargs):
-        return map(self.__class__, unicode.rsplit(self, *args, **kwargs))
-    rsplit.__doc__ = unicode.rsplit.__doc__
+        return map(self.__class__, six.text_type.rsplit(self, *args, **kwargs))
+    rsplit.__doc__ = six.text_type.rsplit.__doc__
 
     def splitlines(self, *args, **kwargs):
-        return map(self.__class__, unicode.splitlines(self, *args, **kwargs))
-    splitlines.__doc__ = unicode.splitlines.__doc__
+        return map(self.__class__, six.text_type.splitlines(self, *args, **kwargs))
+    splitlines.__doc__ = six.text_type.splitlines.__doc__
 
     def unescape(self):
         r"""Unescape markup again into an unicode string.  This also resolves
@@ -167,7 +169,7 @@ class Markup(unicode):
         return rv
 
     def make_wrapper(name):
-        orig = getattr(unicode, name)
+        orig = getattr(six.text_type, name)
         def func(self, *args, **kwargs):
             args = _escape_argspec(list(args), enumerate(args))
             _escape_argspec(kwargs, six.iteritems(kwargs))
@@ -183,16 +185,16 @@ class Markup(unicode):
         locals()[method] = make_wrapper(method)
 
     # new in python 2.5
-    if hasattr(unicode, 'partition'):
+    if hasattr(six.text_type, 'partition'):
         partition = make_wrapper('partition'),
         rpartition = make_wrapper('rpartition')
 
     # new in python 2.6
-    if hasattr(unicode, 'format'):
+    if hasattr(six.text_type, 'format'):
         format = make_wrapper('format')
 
     # not in python 3
-    if hasattr(unicode, '__getslice__'):
+    if hasattr(six.text_type, '__getslice__'):
         __getslice__ = make_wrapper('__getslice__')
 
     del method, make_wrapper
@@ -201,7 +203,7 @@ class Markup(unicode):
 def _escape_argspec(obj, iterable):
     """Helper for various string-wrapped functions."""
     for key, value in iterable:
-        if hasattr(value, '__html__') or isinstance(value, basestring):
+        if hasattr(value, '__html__') or isinstance(value, six.string_types):
             obj[key] = escape(value)
     return obj
 
index 97065bb00130271110c533324eb96920445dd8b7..389be74d374d9634cb37d29d8abf212d8268591b 100644 (file)
@@ -41,6 +41,6 @@ def soft_unicode(s):
     """Make a string unicode if it isn't already.  That way a markup
     string is not converted back to unicode.
     """
-    if not isinstance(s, unicode):
+    if not isinstance(s, six.text_type):
         s = six.text_type(s)
     return s
index 0b0ccad1f243c598fc23c84191275d2570c65330..7c911880edc87d24a873419aceaafe834271ec2f 100644 (file)
@@ -18,7 +18,7 @@ from os import path, listdir
 import sys
 import marshal
 import tempfile
-import cPickle as pickle
+from six.moves import cPickle as pickle
 import fnmatch
 try:
     from hashlib import sha1
index 35f7d0281dcc0f5518939417142a988962eaf636..4ee39f89f793af71b78955fc2d3c297f74eae1cf 100644 (file)
@@ -8,17 +8,16 @@
     :copyright: (c) 2010 by the Jinja Team.
     :license: BSD, see LICENSE for more details.
 """
-from cStringIO import StringIO
 from itertools import chain
 from copy import deepcopy
 from jinja2 import nodes
 from jinja2.nodes import EvalContext
 from jinja2.visitor import NodeVisitor
 from jinja2.exceptions import TemplateAssertionError
-from jinja2.utils import Markup, concat, escape, is_python_keyword, next
+from jinja2.utils import Markup, concat, escape, is_python_keyword
 import six
-from six.moves import map
-from six.moves import zip
+from six.moves import cStringIO as StringIO
+from six.moves import map, zip
 
 
 operators = {
@@ -72,8 +71,11 @@ def has_safe_repr(value):
     """Does the node have a safe representation?"""
     if value is None or value is NotImplemented or value is Ellipsis:
         return True
-    if isinstance(value, (bool, int, long, float, complex, basestring,
-                          xrange, Markup)):
+    try:
+        range_type = xrange
+    except NameError:
+        range_type = range
+    if isinstance(value, (bool, int, float, complex, range_type, Markup) + six.string_types):
         return True
     if isinstance(value, (tuple, list, set, frozenset)):
         for item in value:
@@ -933,7 +935,7 @@ class CodeGenerator(NodeVisitor):
 
         func_name = 'get_or_select_template'
         if isinstance(node.template, nodes.Const):
-            if isinstance(node.template.value, basestring):
+            if isinstance(node.template.value, six.string_types):
                 func_name = 'get_template'
             elif isinstance(node.template.value, (tuple, list)):
                 func_name = 'select_template'
@@ -1221,7 +1223,7 @@ class CodeGenerator(NodeVisitor):
         if self.environment.finalize:
             finalize = lambda x: six.text_type(self.environment.finalize(x))
         else:
-            finalize = unicode
+            finalize = six.text_type
 
         # if we are inside a frame that requires output checking, we do so
         outdent_later = False
@@ -1355,7 +1357,7 @@ class CodeGenerator(NodeVisitor):
             public_names = [x for x in assignment_frame.toplevel_assignments
                             if not x.startswith('_')]
             if len(assignment_frame.toplevel_assignments) == 1:
-                name = next(iter(assignment_frame.toplevel_assignments))
+                name = six.advance_iterator(iter(assignment_frame.toplevel_assignments))
                 self.writeline('context.vars[%r] = l_%s' % (name, name))
             else:
                 self.writeline('context.vars.update({')
index c653e3667a1310431a3f0ad56a8a83891c881a0c..55c12fe62828d4f6ca684e1fa10b4cf8d7c081dc 100644 (file)
@@ -190,7 +190,7 @@ def translate_exception(exc_info, initial_skip=0):
     # reraise it unchanged.
     # XXX: can we backup here?  when could this happen?
     if not frames:
-        raise exc_info[0], exc_info[1], exc_info[2]
+        six.reraise(exc_info[0], exc_info[1], exc_info[2])
 
     return ProcessedTraceback(exc_info[0], exc_info[1], frames)
 
index d2d45443adde9d94b1319bc4ffa54a5abbe99baf..97b17ee7bec007395a5392454742b080d2c55d4d 100644 (file)
@@ -8,6 +8,7 @@
     :copyright: (c) 2010 by the Jinja Team.
     :license: BSD, see LICENSE for more details.
 """
+from six.moves import xrange
 from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner
 
 
index 71f022f3e970f00559ffda7083e2c501d51caf25..a8149c71b0259a25d6b1ba9ec59fe83388b1f634 100644 (file)
@@ -23,9 +23,7 @@ from jinja2.utils import import_string, LRUCache, Markup, missing, \
      concat, consume, internalcode, _encode_filename
 import six
 from functools import reduce
-from six.moves import filter
-from six.moves import map
-from six.moves import zip
+from six.moves import filter, map, zip
 
 
 # for direct template usage we have up to ten living environments
@@ -76,7 +74,7 @@ def load_extensions(environment, extensions):
     """
     result = {}
     for extension in extensions:
-        if isinstance(extension, basestring):
+        if isinstance(extension, six.string_types):
             extension = import_string(extension)
         result[extension.identifier] = extension(environment)
     return result
@@ -357,7 +355,7 @@ class Environment(object):
         try:
             return obj[argument]
         except (TypeError, LookupError):
-            if isinstance(argument, basestring):
+            if isinstance(argument, six.string_types):
                 try:
                     attr = str(argument)
                 except Exception:
@@ -479,7 +477,7 @@ class Environment(object):
         """
         source_hint = None
         try:
-            if isinstance(source, basestring):
+            if isinstance(source, six.string_types):
                 source_hint = source
                 source = self._parse(source, name, filename)
             if self.optimized:
@@ -676,7 +674,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
+        six.reraise(exc_type, exc_value, tb)
 
     def join_path(self, template, parent):
         """Join a template with the parent.  By default all the lookups are
@@ -763,7 +761,7 @@ class Environment(object):
 
         .. versionadded:: 2.3
         """
-        if isinstance(template_name_or_list, basestring):
+        if isinstance(template_name_or_list, six.string_types):
             return self.get_template(template_name_or_list, parent, globals)
         elif isinstance(template_name_or_list, Template):
             return template_name_or_list
@@ -1008,12 +1006,9 @@ class TemplateModule(object):
         return Markup(concat(self._body_stream))
 
     def __str__(self):
-        return six.text_type(self).encode('utf-8')
+        s = self.__unicode__()
+        return s if six.PY3 else s.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)
 
@@ -1044,7 +1039,7 @@ class TemplateExpression(object):
         return rv
 
 
-class TemplateStream(object):
+class TemplateStream(six.Iterator):
     """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
@@ -1069,7 +1064,7 @@ class TemplateStream(object):
             Template('Hello {{ name }}!').stream(name='foo').dump('hello.html')
         """
         close = False
-        if isinstance(fp, basestring):
+        if isinstance(fp, six.string_types):
             fp = file(fp, 'w')
             close = True
         try:
@@ -1088,7 +1083,7 @@ class TemplateStream(object):
 
     def disable_buffering(self):
         """Disable the output buffering."""
-        self._next = self._gen.next
+        self._next = lambda: six.next(self._gen)
         self.buffered = False
 
     def enable_buffering(self, size=5):
@@ -1116,12 +1111,12 @@ class TemplateStream(object):
                 c_size = 0
 
         self.buffered = True
-        self._next = generator(self._gen.next).next
+        self._next = lambda: six.next(generator(lambda: six.next(self._gen)))
 
     def __iter__(self):
         return self
 
-    def next(self):
+    def __next__(self):
         return self._next()
 
 
index 90025210ace5311b22da3729b767ed99cc559ff9..f38d34745e2a81981e37fc4ff2172b46540b24df 100644 (file)
@@ -9,8 +9,7 @@
     :license: BSD, see LICENSE for more details.
 """
 import six
-from six.moves import map
-from six.moves import zip
+from six.moves import map, zip
 
 
 class TemplateError(Exception):
@@ -66,7 +65,7 @@ class TemplatesNotFound(TemplateNotFound):
     def __init__(self, names=(), message=None):
         if message is None:
             message = u'none of the templates given were found: ' + \
-                      u', '.join(map(unicode, names))
+                      u', '.join(map(six.text_type, names))
         TemplateNotFound.__init__(self, names and names[-1] or None, message)
         self.templates = list(names)
 
@@ -86,12 +85,9 @@ class TemplateSyntaxError(TemplateError):
         self.translated = False
 
     def __str__(self):
-        return six.text_type(self).encode('utf-8')
+        s = self.__unicode__()
+        return s if six.PY3 else s.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
         if self.translated:
index 984a4d958da7fdbd27865ff40c8386952276c48c..0652a3403138b0d9f30b62e16baea466bd2c0084 100644 (file)
@@ -16,7 +16,7 @@ from jinja2.defaults import *
 from jinja2.environment import Environment
 from jinja2.runtime import Undefined, concat
 from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError
-from jinja2.utils import contextfunction, import_string, Markup, next
+from jinja2.utils import contextfunction, import_string, Markup
 import six
 
 
@@ -35,7 +35,7 @@ class ExtensionRegistry(type):
         return rv
 
 
-class Extension(object):
+class Extension(six.with_metaclass(ExtensionRegistry, object)):
     """Extensions can be used to add extra functionality to the Jinja template
     system at the parser level.  Custom extensions are bound to an environment
     but may not store environment specific data on `self`.  The reason for
@@ -206,13 +206,13 @@ class InternationalizationExtension(Extension):
             self.environment.globals.pop(key, None)
 
     def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS):
-        if isinstance(source, basestring):
+        if isinstance(source, six.string_types):
             source = self.environment.parse(source)
         return extract_from_ast(source, gettext_functions)
 
     def parse(self, parser):
         """Parse a translatable tag."""
-        lineno = next(parser.stream).lineno
+        lineno = six.advance_iterator(parser.stream).lineno
         num_called_num = False
 
         # find all the variables referenced.  Additionally a variable can be
@@ -236,7 +236,7 @@ class InternationalizationExtension(Extension):
 
             # expressions
             if parser.stream.current.type == 'assign':
-                next(parser.stream)
+                six.advance_iterator(parser.stream)
                 variables[name.value] = var = parser.parse_expression()
             else:
                 variables[name.value] = var = nodes.Name(name.value, 'load')
@@ -262,7 +262,7 @@ class InternationalizationExtension(Extension):
         # if we have a pluralize block, we parse that too
         if parser.stream.current.test('name:pluralize'):
             have_plural = True
-            next(parser.stream)
+            six.advance_iterator(parser.stream)
             if parser.stream.current.type != 'block_end':
                 name = parser.stream.expect('name')
                 if name.value not in variables:
@@ -273,10 +273,10 @@ class InternationalizationExtension(Extension):
                 num_called_num = name.value == 'num'
             parser.stream.expect('block_end')
             plural_names, plural = self._parse_block(parser, False)
-            next(parser.stream)
+            six.advance_iterator(parser.stream)
             referenced.update(plural_names)
         else:
-            next(parser.stream)
+            six.advance_iterator(parser.stream)
 
         # register free names as simple name expressions
         for var in referenced:
@@ -301,15 +301,15 @@ class InternationalizationExtension(Extension):
         while 1:
             if parser.stream.current.type == 'data':
                 buf.append(parser.stream.current.value.replace('%', '%%'))
-                next(parser.stream)
+                six.advance_iterator(parser.stream)
             elif parser.stream.current.type == 'variable_begin':
-                next(parser.stream)
+                six.advance_iterator(parser.stream)
                 name = parser.stream.expect('name').value
                 referenced.append(name)
                 buf.append('%%(%s)s' % name)
                 parser.stream.expect('variable_end')
             elif parser.stream.current.type == 'block_begin':
-                next(parser.stream)
+                six.advance_iterator(parser.stream)
                 if parser.stream.current.test('name:endtrans'):
                     break
                 elif parser.stream.current.test('name:pluralize'):
@@ -382,7 +382,7 @@ class ExprStmtExtension(Extension):
     tags = set(['do'])
 
     def parse(self, parser):
-        node = nodes.ExprStmt(lineno=next(parser.stream).lineno)
+        node = nodes.ExprStmt(lineno=six.advance_iterator(parser.stream).lineno)
         node.node = parser.parse_tuple()
         return node
 
@@ -392,7 +392,7 @@ class LoopControlExtension(Extension):
     tags = set(['break', 'continue'])
 
     def parse(self, parser):
-        token = next(parser.stream)
+        token = six.advance_iterator(parser.stream)
         if token.value == 'break':
             return nodes.Break(lineno=token.lineno)
         return nodes.Continue(lineno=token.lineno)
@@ -403,7 +403,7 @@ class WithExtension(Extension):
     tags = set(['with'])
 
     def parse(self, parser):
-        node = nodes.Scope(lineno=next(parser.stream).lineno)
+        node = nodes.Scope(lineno=six.advance_iterator(parser.stream).lineno)
         assignments = []
         while parser.stream.current.type != 'block_end':
             lineno = parser.stream.current.lineno
@@ -424,7 +424,7 @@ class AutoEscapeExtension(Extension):
     tags = set(['autoescape'])
 
     def parse(self, parser):
-        node = nodes.ScopedEvalContextModifier(lineno=next(parser.stream).lineno)
+        node = nodes.ScopedEvalContextModifier(lineno=six.advance_iterator(parser.stream).lineno)
         node.options = [
             nodes.Keyword('autoescape', parser.parse_expression())
         ]
@@ -477,7 +477,7 @@ def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS,
         strings = []
         for arg in node.args:
             if isinstance(arg, nodes.Const) and \
-               isinstance(arg.value, basestring):
+               isinstance(arg.value, six.string_types):
                 strings.append(arg.value)
             else:
                 strings.append(None)
index 43387aeb3da35b18d7b2674ab6586b6c929dd134..d137fc57e82975635ab4fd551db0d45619b373d0 100644 (file)
@@ -12,14 +12,13 @@ import re
 import math
 from random import choice
 from operator import itemgetter
-from itertools import imap, groupby
+from itertools import groupby
 from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \
      unicode_urlencode
 from jinja2.runtime import Undefined
 from jinja2.exceptions import FilterArgumentError
 import six
-from six.moves import map
-from six.moves import zip
+from six.moves import map, zip
 
 
 _word_re = re.compile(r'\w+(?u)')
@@ -57,7 +56,7 @@ def make_attrgetter(environment, attribute):
     passed object with the rules of the environment.  Dots are allowed
     to access attributes of attributes.
     """
-    if not isinstance(attribute, basestring) or '.' not in attribute:
+    if not isinstance(attribute, six.string_types) or '.' not in attribute:
         return lambda x: environment.getitem(x, attribute)
     attribute = attribute.split('.')
     def attrgetter(item):
@@ -83,7 +82,7 @@ def do_urlencode(value):
     itemiter = None
     if isinstance(value, dict):
         itemiter = six.iteritems(value)
-    elif not isinstance(value, basestring):
+    elif not isinstance(value, six.string_types):
         try:
             itemiter = iter(value)
         except TypeError:
@@ -213,7 +212,7 @@ def do_dictsort(value, case_sensitive=False, by='key'):
                                   '"key" or "value"')
     def sort_func(item):
         value = item[pos]
-        if isinstance(value, basestring) and not case_sensitive:
+        if isinstance(value, six.string_types) and not case_sensitive:
             value = value.lower()
         return value
 
@@ -250,7 +249,7 @@ def do_sort(environment, value, reverse=False, case_sensitive=False,
     """
     if not case_sensitive:
         def sort_func(item):
-            if isinstance(item, basestring):
+            if isinstance(item, six.string_types):
                 item = item.lower()
             return item
     else:
@@ -308,11 +307,11 @@ def do_join(eval_ctx, value, d=u'', attribute=None):
        The `attribute` parameter was added.
     """
     if attribute is not None:
-        value = imap(make_attrgetter(eval_ctx.environment, attribute), value)
+        value = map(make_attrgetter(eval_ctx.environment, attribute), value)
 
     # no automatic escaping?  joining is a lot eaiser then
     if not eval_ctx.autoescape:
-        return six.text_type(d).join(imap(unicode, value))
+        return six.text_type(d).join(map(six.text_type, value))
 
     # if the delimiter doesn't have an html representation we check
     # if any of the items has.  If yes we do a coercion to Markup
@@ -331,7 +330,7 @@ def do_join(eval_ctx, value, d=u'', attribute=None):
         return d.join(value)
 
     # no html involved, to normal joining
-    return soft_unicode(d).join(imap(soft_unicode, value))
+    return soft_unicode(d).join(map(soft_unicode, value))
 
 
 def do_center(value, width=80):
@@ -717,7 +716,7 @@ def do_sum(environment, iterable, attribute=None, start=0):
        attributes.  Also the `start` parameter was moved on to the right.
     """
     if attribute is not None:
-        iterable = imap(make_attrgetter(environment, attribute), iterable)
+        iterable = map(make_attrgetter(environment, attribute), iterable)
     return sum(iterable, start)
 
 
@@ -744,7 +743,7 @@ def do_reverse(value):
     """Reverse the object or return an iterator the iterates over it the other
     way round.
     """
-    if isinstance(value, basestring):
+    if isinstance(value, six.string_types):
         return value[::-1]
     try:
         return reversed(value)
index 5d24718f3ac500cdd2441a96e1a974a72911b071..d56bc678e0b19fb2ed3d161122f38447835055c9 100644 (file)
@@ -18,7 +18,7 @@ import re
 from operator import itemgetter
 from collections import deque
 from jinja2.exceptions import TemplateSyntaxError
-from jinja2.utils import LRUCache, next
+from jinja2.utils import LRUCache
 import six
 
 
@@ -46,6 +46,12 @@ else:
 float_re = re.compile(r'(?<!\.)\d+\.\d+')
 newline_re = re.compile(r'(\r\n|\r|\n)')
 
+try:
+    intern = intern  # py2
+except NameError:
+    import sys
+    intern = sys.intern  # py3
+
 # internal the tokens and keep references to them
 TOKEN_ADD = intern('add')
 TOKEN_ASSIGN = intern('assign')
@@ -263,7 +269,7 @@ class Token(tuple):
         )
 
 
-class TokenStreamIterator(object):
+class TokenStreamIterator(six.Iterator):
     """The iterator for tokenstreams.  Iterate over the stream
     until the eof token is reached.
     """
@@ -274,35 +280,36 @@ class TokenStreamIterator(object):
     def __iter__(self):
         return self
 
-    def next(self):
+    def __next__(self):
         token = self.stream.current
         if token.type is TOKEN_EOF:
             self.stream.close()
             raise StopIteration()
-        next(self.stream)
+        six.advance_iterator(self.stream)
         return token
 
 
-class TokenStream(object):
+class TokenStream(six.Iterator):
     """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
     one token ahead.  The current active token is stored as :attr:`current`.
     """
 
     def __init__(self, generator, name, filename):
-        self._next = iter(generator).next
+        self._iter = iter(generator)
         self._pushed = deque()
         self.name = name
         self.filename = filename
         self.closed = False
         self.current = Token(1, TOKEN_INITIAL, '')
-        next(self)
+        six.advance_iterator(self)
 
     def __iter__(self):
         return TokenStreamIterator(self)
 
-    def __nonzero__(self):
+    def __bool__(self):
         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?")
 
@@ -312,7 +319,7 @@ class TokenStream(object):
 
     def look(self):
         """Look at the next token."""
-        old_token = next(self)
+        old_token = six.advance_iterator(self)
         result = self.current
         self.push(result)
         self.current = old_token
@@ -321,27 +328,27 @@ class TokenStream(object):
     def skip(self, n=1):
         """Got n tokens ahead."""
         for x in range(n):
-            next(self)
+            six.advance_iterator(self)
 
     def next_if(self, expr):
         """Perform the token test and return the token if it matched.
         Otherwise the return value is `None`.
         """
         if self.current.test(expr):
-            return next(self)
+            return six.advance_iterator(self)
 
     def skip_if(self, expr):
         """Like :meth:`next_if` but only returns `True` or `False`."""
         return self.next_if(expr) is not None
 
-    def next(self):
+    def __next__(self):
         """Go one token ahead and return the old one"""
         rv = self.current
         if self._pushed:
             self.current = self._pushed.popleft()
         elif self.current.type is not TOKEN_EOF:
             try:
-                self.current = self._next()
+                self.current = six.advance_iterator(self._iter)
             except StopIteration:
                 self.close()
         return rv
@@ -349,7 +356,7 @@ class TokenStream(object):
     def close(self):
         """Close the stream."""
         self.current = Token(self.current.lineno, TOKEN_EOF, '')
-        self._next = None
+        self._iter = None
         self.closed = True
 
     def expect(self, expr):
@@ -370,7 +377,7 @@ class TokenStream(object):
         try:
             return self.current
         finally:
-            next(self)
+            six.advance_iterator(self)
 
 
 def get_lexer(environment):
index a27492278b94cf68a3430b91683e0bcde24a88b5..809dad0477bb6cfa4cdeeed75c37fb1ef4347623 100644 (file)
@@ -154,7 +154,7 @@ class FileSystemLoader(BaseLoader):
     """
 
     def __init__(self, searchpath, encoding='utf-8'):
-        if isinstance(searchpath, basestring):
+        if isinstance(searchpath, six.string_types):
             searchpath = [searchpath]
         self.searchpath = list(searchpath)
         self.encoding = encoding
@@ -307,7 +307,7 @@ class FunctionLoader(BaseLoader):
         rv = self.load_func(template)
         if rv is None:
             raise TemplateNotFound(template)
-        elif isinstance(rv, basestring):
+        elif isinstance(rv, six.string_types):
             return rv, None, None
         return rv
 
@@ -432,7 +432,7 @@ class ModuleLoader(BaseLoader):
         # create a fake module that looks for the templates in the
         # path given.
         mod = _TemplateModule(package_name)
-        if isinstance(path, basestring):
+        if isinstance(path, six.string_types):
             path = [path]
         else:
             path = list(path)
index 3a779a5e9a81a6b59b0fa1685c63e62e38a70b9c..26ae0b93d02f834bf27ed0de3bf2344aebea31fb 100644 (file)
@@ -11,7 +11,7 @@
 """
 from jinja2 import nodes
 from jinja2.compiler import CodeGenerator
-
+import six
 
 class TrackingCodeGenerator(CodeGenerator):
     """We abuse the code generator for introspection."""
@@ -77,7 +77,7 @@ def find_referenced_templates(ast):
                     # something const, only yield the strings and ignore
                     # non-string consts that really just make no sense
                     if isinstance(template_name, nodes.Const):
-                        if isinstance(template_name.value, basestring):
+                        if isinstance(template_name.value, six.string_types):
                             yield template_name.value
                     # something dynamic in there
                     else:
@@ -87,7 +87,7 @@ def find_referenced_templates(ast):
                 yield None
             continue
         # constant is a basestring, direct template name
-        if isinstance(node.template.value, basestring):
+        if isinstance(node.template.value, six.string_types):
             yield node.template.value
         # a tuple or list (latter *should* not happen) made of consts,
         # yield the consts that are strings.  We could warn here for
@@ -95,7 +95,7 @@ def find_referenced_templates(ast):
         elif isinstance(node, nodes.Include) and \
              isinstance(node.template.value, (tuple, list)):
             for template_name in node.template.value:
-                if isinstance(template_name, basestring):
+                if isinstance(template_name, six.string_types):
                     yield template_name
         # something else we don't care about, we could warn here
         else:
index 5651a41cce3b6cae448ddda323e5b89fa89a1226..c14f8e386692cd72378d53eaddcb8ee761214fb5 100644 (file)
     :license: BSD, see LICENSE for more details.
 """
 import operator
-from itertools import chain, izip
 from collections import deque
 from jinja2.utils import Markup, MethodType, FunctionType
 import six
+from six.moves import zip
 
 
 #: the types we support for context functions
@@ -103,7 +103,7 @@ def get_eval_context(node, ctx):
     return ctx
 
 
-class Node(object):
+class Node(six.with_metaclass(NodeType, object)):
     """Baseclass for all Jinja2 nodes.  There are a number of nodes available
     of different types.  There are three major types:
 
@@ -137,7 +137,7 @@ class Node(object):
                     len(self.fields),
                     len(self.fields) != 1 and 's' or ''
                 ))
-            for name, arg in izip(self.fields, fields):
+            for name, arg in zip(self.fields, fields):
                 setattr(self, name, arg)
         for attr in self.attributes:
             setattr(self, attr, attributes.pop(attr, None))
index b4b06fe85d7d24a37e1ba8340f169c5ecdc2c272..520e88fa9ae554664877d41df7f3eaa6fc97767a 100644 (file)
 """
 from jinja2 import nodes
 from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
-from jinja2.utils import next
 from jinja2.lexer import describe_token, describe_token_expr
-from six.moves import map
-from six.moves import zip
+import six
+from six.moves import map, zip
 
 
 #: statements that callinto 
@@ -164,12 +163,12 @@ class Parser(object):
             self.fail_eof(end_tokens)
 
         if drop_needle:
-            next(self.stream)
+            six.advance_iterator(self.stream)
         return result
 
     def parse_set(self):
         """Parse an assign statement."""
-        lineno = next(self.stream).lineno
+        lineno = six.advance_iterator(self.stream).lineno
         target = self.parse_assign_target()
         self.stream.expect('assign')
         expr = self.parse_tuple()
@@ -187,7 +186,7 @@ class Parser(object):
             test = self.parse_expression()
         recursive = self.stream.skip_if('name:recursive')
         body = self.parse_statements(('name:endfor', 'name:else'))
-        if next(self.stream).value == 'endfor':
+        if six.advance_iterator(self.stream).value == 'endfor':
             else_ = []
         else:
             else_ = self.parse_statements(('name:endfor',), drop_needle=True)
@@ -201,7 +200,7 @@ class Parser(object):
             node.test = self.parse_tuple(with_condexpr=False)
             node.body = self.parse_statements(('name:elif', 'name:else',
                                                'name:endif'))
-            token = next(self.stream)
+            token = six.advance_iterator(self.stream)
             if token.test('name:elif'):
                 new_node = nodes.If(lineno=self.stream.current.lineno)
                 node.else_ = [new_node]
@@ -216,7 +215,7 @@ class Parser(object):
         return result
 
     def parse_block(self):
-        node = nodes.Block(lineno=next(self.stream).lineno)
+        node = nodes.Block(lineno=six.advance_iterator(self.stream).lineno)
         node.name = self.stream.expect('name').value
         node.scoped = self.stream.skip_if('name:scoped')
 
@@ -233,21 +232,21 @@ class Parser(object):
         return node
 
     def parse_extends(self):
-        node = nodes.Extends(lineno=next(self.stream).lineno)
+        node = nodes.Extends(lineno=six.advance_iterator(self.stream).lineno)
         node.template = self.parse_expression()
         return node
 
     def parse_import_context(self, node, default):
         if self.stream.current.test_any('name:with', 'name:without') and \
            self.stream.look().test('name:context'):
-            node.with_context = next(self.stream).value == 'with'
+            node.with_context = six.advance_iterator(self.stream).value == 'with'
             self.stream.skip()
         else:
             node.with_context = default
         return node
 
     def parse_include(self):
-        node = nodes.Include(lineno=next(self.stream).lineno)
+        node = nodes.Include(lineno=six.advance_iterator(self.stream).lineno)
         node.template = self.parse_expression()
         if self.stream.current.test('name:ignore') and \
            self.stream.look().test('name:missing'):
@@ -258,14 +257,14 @@ class Parser(object):
         return self.parse_import_context(node, True)
 
     def parse_import(self):
-        node = nodes.Import(lineno=next(self.stream).lineno)
+        node = nodes.Import(lineno=six.advance_iterator(self.stream).lineno)
         node.template = self.parse_expression()
         self.stream.expect('name:as')
         node.target = self.parse_assign_target(name_only=True).name
         return self.parse_import_context(node, False)
 
     def parse_from(self):
-        node = nodes.FromImport(lineno=next(self.stream).lineno)
+        node = nodes.FromImport(lineno=six.advance_iterator(self.stream).lineno)
         node.template = self.parse_expression()
         self.stream.expect('name:import')
         node.names = []
@@ -273,7 +272,7 @@ class Parser(object):
         def parse_context():
             if self.stream.current.value in ('with', 'without') and \
                self.stream.look().test('name:context'):
-                node.with_context = next(self.stream).value == 'with'
+                node.with_context = six.advance_iterator(self.stream).value == 'with'
                 self.stream.skip()
                 return True
             return False
@@ -318,7 +317,7 @@ class Parser(object):
         self.stream.expect('rparen')
 
     def parse_call_block(self):
-        node = nodes.CallBlock(lineno=next(self.stream).lineno)
+        node = nodes.CallBlock(lineno=six.advance_iterator(self.stream).lineno)
         if self.stream.current.type == 'lparen':
             self.parse_signature(node)
         else:
@@ -332,14 +331,14 @@ class Parser(object):
         return node
 
     def parse_filter_block(self):
-        node = nodes.FilterBlock(lineno=next(self.stream).lineno)
+        node = nodes.FilterBlock(lineno=six.advance_iterator(self.stream).lineno)
         node.filter = self.parse_filter(None, start_inline=True)
         node.body = self.parse_statements(('name:endfilter',),
                                           drop_needle=True)
         return node
 
     def parse_macro(self):
-        node = nodes.Macro(lineno=next(self.stream).lineno)
+        node = nodes.Macro(lineno=six.advance_iterator(self.stream).lineno)
         node.name = self.parse_assign_target(name_only=True).name
         self.parse_signature(node)
         node.body = self.parse_statements(('name:endmacro',),
@@ -347,7 +346,7 @@ class Parser(object):
         return node
 
     def parse_print(self):
-        node = nodes.Output(lineno=next(self.stream).lineno)
+        node = nodes.Output(lineno=six.advance_iterator(self.stream).lineno)
         node.nodes = []
         while self.stream.current.type != 'block_end':
             if node.nodes:
@@ -421,7 +420,7 @@ class Parser(object):
 
     def parse_not(self):
         if self.stream.current.test('name:not'):
-            lineno = next(self.stream).lineno
+            lineno = six.advance_iterator(self.stream).lineno
             return nodes.Not(self.parse_not(), lineno=lineno)
         return self.parse_compare()
 
@@ -432,7 +431,7 @@ class Parser(object):
         while 1:
             token_type = self.stream.current.type
             if token_type in _compare_operators:
-                next(self.stream)
+                six.advance_iterator(self.stream)
                 ops.append(nodes.Operand(token_type, self.parse_add()))
             elif self.stream.skip_if('name:in'):
                 ops.append(nodes.Operand('in', self.parse_add()))
@@ -451,7 +450,7 @@ class Parser(object):
         lineno = self.stream.current.lineno
         left = self.parse_sub()
         while self.stream.current.type == 'add':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             right = self.parse_sub()
             left = nodes.Add(left, right, lineno=lineno)
             lineno = self.stream.current.lineno
@@ -461,7 +460,7 @@ class Parser(object):
         lineno = self.stream.current.lineno
         left = self.parse_concat()
         while self.stream.current.type == 'sub':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             right = self.parse_concat()
             left = nodes.Sub(left, right, lineno=lineno)
             lineno = self.stream.current.lineno
@@ -471,7 +470,7 @@ class Parser(object):
         lineno = self.stream.current.lineno
         args = [self.parse_mul()]
         while self.stream.current.type == 'tilde':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             args.append(self.parse_mul())
         if len(args) == 1:
             return args[0]
@@ -481,7 +480,7 @@ class Parser(object):
         lineno = self.stream.current.lineno
         left = self.parse_div()
         while self.stream.current.type == 'mul':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             right = self.parse_div()
             left = nodes.Mul(left, right, lineno=lineno)
             lineno = self.stream.current.lineno
@@ -491,7 +490,7 @@ class Parser(object):
         lineno = self.stream.current.lineno
         left = self.parse_floordiv()
         while self.stream.current.type == 'div':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             right = self.parse_floordiv()
             left = nodes.Div(left, right, lineno=lineno)
             lineno = self.stream.current.lineno
@@ -501,7 +500,7 @@ class Parser(object):
         lineno = self.stream.current.lineno
         left = self.parse_mod()
         while self.stream.current.type == 'floordiv':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             right = self.parse_mod()
             left = nodes.FloorDiv(left, right, lineno=lineno)
             lineno = self.stream.current.lineno
@@ -511,7 +510,7 @@ class Parser(object):
         lineno = self.stream.current.lineno
         left = self.parse_pow()
         while self.stream.current.type == 'mod':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             right = self.parse_pow()
             left = nodes.Mod(left, right, lineno=lineno)
             lineno = self.stream.current.lineno
@@ -521,7 +520,7 @@ class Parser(object):
         lineno = self.stream.current.lineno
         left = self.parse_unary()
         while self.stream.current.type == 'pow':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             right = self.parse_unary()
             left = nodes.Pow(left, right, lineno=lineno)
             lineno = self.stream.current.lineno
@@ -531,10 +530,10 @@ class Parser(object):
         token_type = self.stream.current.type
         lineno = self.stream.current.lineno
         if token_type == 'sub':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             node = nodes.Neg(self.parse_unary(False), lineno=lineno)
         elif token_type == 'add':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             node = nodes.Pos(self.parse_unary(False), lineno=lineno)
         else:
             node = self.parse_primary()
@@ -553,20 +552,20 @@ class Parser(object):
                 node = nodes.Const(None, lineno=token.lineno)
             else:
                 node = nodes.Name(token.value, 'load', lineno=token.lineno)
-            next(self.stream)
+            six.advance_iterator(self.stream)
         elif token.type == 'string':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             buf = [token.value]
             lineno = token.lineno
             while self.stream.current.type == 'string':
                 buf.append(self.stream.current.value)
-                next(self.stream)
+                six.advance_iterator(self.stream)
             node = nodes.Const(''.join(buf), lineno=lineno)
         elif token.type in ('integer', 'float'):
-            next(self.stream)
+            six.advance_iterator(self.stream)
             node = nodes.Const(token.value, lineno=token.lineno)
         elif token.type == 'lparen':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             node = self.parse_tuple(explicit_parentheses=True)
             self.stream.expect('rparen')
         elif token.type == 'lbracket':
@@ -688,10 +687,10 @@ class Parser(object):
         return node
 
     def parse_subscript(self, node):
-        token = next(self.stream)
+        token = six.advance_iterator(self.stream)
         if token.type == 'dot':
             attr_token = self.stream.current
-            next(self.stream)
+            six.advance_iterator(self.stream)
             if attr_token.type == 'name':
                 return nodes.Getattr(node, attr_token.value, 'load',
                                      lineno=token.lineno)
@@ -717,13 +716,13 @@ class Parser(object):
         lineno = self.stream.current.lineno
 
         if self.stream.current.type == 'colon':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             args = [None]
         else:
             node = self.parse_expression()
             if self.stream.current.type != 'colon':
                 return node
-            next(self.stream)
+            six.advance_iterator(self.stream)
             args = [node]
 
         if self.stream.current.type == 'colon':
@@ -734,7 +733,7 @@ class Parser(object):
             args.append(None)
 
         if self.stream.current.type == 'colon':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             if self.stream.current.type not in ('rbracket', 'comma'):
                 args.append(self.parse_expression())
             else:
@@ -764,11 +763,11 @@ class Parser(object):
                     break
             if self.stream.current.type == 'mul':
                 ensure(dyn_args is None and dyn_kwargs is None)
-                next(self.stream)
+                six.advance_iterator(self.stream)
                 dyn_args = self.parse_expression()
             elif self.stream.current.type == 'pow':
                 ensure(dyn_kwargs is None)
-                next(self.stream)
+                six.advance_iterator(self.stream)
                 dyn_kwargs = self.parse_expression()
             else:
                 ensure(dyn_args is None and dyn_kwargs is None)
@@ -794,11 +793,11 @@ class Parser(object):
     def parse_filter(self, node, start_inline=False):
         while self.stream.current.type == 'pipe' or start_inline:
             if not start_inline:
-                next(self.stream)
+                six.advance_iterator(self.stream)
             token = self.stream.expect('name')
             name = token.value
             while self.stream.current.type == 'dot':
-                next(self.stream)
+                six.advance_iterator(self.stream)
                 name += '.' + self.stream.expect('name').value
             if self.stream.current.type == 'lparen':
                 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
@@ -812,15 +811,15 @@ class Parser(object):
         return node
 
     def parse_test(self, node):
-        token = next(self.stream)
+        token = six.advance_iterator(self.stream)
         if self.stream.current.test('name:not'):
-            next(self.stream)
+            six.advance_iterator(self.stream)
             negated = True
         else:
             negated = False
         name = self.stream.expect('name').value
         while self.stream.current.type == 'dot':
-            next(self.stream)
+            six.advance_iterator(self.stream)
             name += '.' + self.stream.expect('name').value
         dyn_args = dyn_kwargs = None
         kwargs = []
@@ -863,14 +862,14 @@ class Parser(object):
                     if token.value:
                         add_data(nodes.TemplateData(token.value,
                                                     lineno=token.lineno))
-                    next(self.stream)
+                    six.advance_iterator(self.stream)
                 elif token.type == 'variable_begin':
-                    next(self.stream)
+                    six.advance_iterator(self.stream)
                     add_data(self.parse_tuple(with_condexpr=True))
                     self.stream.expect('variable_end')
                 elif token.type == 'block_begin':
                     flush_data()
-                    next(self.stream)
+                    six.advance_iterator(self.stream)
                     if end_tokens is not None and \
                        self.stream.current.test_any(*end_tokens):
                         return body
index 750b630a1a8fa1ab0bf8c704b5d48ec15c0cd518..a11095e44c197c5f5abd1ed8235c81053c8d98ef 100644 (file)
@@ -8,13 +8,14 @@
     :copyright: (c) 2010 by the Jinja Team.
     :license: BSD.
 """
-from itertools import chain, imap
+from itertools import chain
 from jinja2.nodes import EvalContext, _context_function_types
 from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \
-     concat, internalcode, next, object_type_repr
+     concat, internalcode, object_type_repr
 from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
      TemplateNotFound
 import six
+from six.moves import map
 
 
 # these variables are exported to the template runtime
@@ -26,7 +27,10 @@ __all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
 #: the name of the function that is used to convert something into
 #: a string.  2to3 will adopt that automatically and the generated
 #: code can take advantage of it.
-to_string = unicode
+try:
+    to_string = unicode
+except NameError:
+    to_string = str
 
 #: the identity function.  Useful for certain things in the environment
 identity = lambda x: x
@@ -37,7 +41,7 @@ _last_iteration = object()
 def markup_join(seq):
     """Concatenation that escapes if necessary and converts to unicode."""
     buf = []
-    iterator = imap(soft_unicode, seq)
+    iterator = map(soft_unicode, seq)
     for arg in iterator:
         buf.append(arg)
         if hasattr(arg, '__html__'):
@@ -47,7 +51,7 @@ def markup_join(seq):
 
 def unicode_join(seq):
     """Simple args to unicode conversion and concatenation."""
-    return concat(imap(unicode, seq))
+    return concat(map(six.text_type, seq))
 
 
 def new_context(environment, template_name, blocks, vars=None,
@@ -305,7 +309,7 @@ class LoopContext(object):
 
     def _safe_next(self):
         try:
-            return next(self._iterator)
+            return six.advance_iterator(self._iterator)
         except StopIteration:
             return _last_iteration
 
@@ -341,7 +345,7 @@ class LoopContext(object):
         )
 
 
-class LoopContextIterator(object):
+class LoopContextIterator(six.Iterator):
     """The iterator for a loop context."""
     __slots__ = ('context',)
 
@@ -351,7 +355,7 @@ class LoopContextIterator(object):
     def __iter__(self):
         return self
 
-    def next(self):
+    def __next__(self):
         ctx = self.context
         ctx.index0 += 1
         if ctx._after is _last_iteration:
@@ -456,7 +460,7 @@ class Undefined(object):
         if self._undefined_hint is None:
             if self._undefined_obj is missing:
                 hint = '%r is undefined' % self._undefined_name
-            elif not isinstance(self._undefined_name, basestring):
+            elif not isinstance(self._undefined_name, six.string_types):
                 hint = '%s has no element %r' % (
                     object_type_repr(self._undefined_obj),
                     self._undefined_name
@@ -484,12 +488,9 @@ class Undefined(object):
         _fail_with_undefined_error
 
     def __str__(self):
-        return six.text_type(self).encode('utf-8')
+        s = self.__unicode__()
+        return s if six.PY3 else s.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''
 
@@ -522,6 +523,10 @@ class DebugUndefined(Undefined):
     """
     __slots__ = ()
 
+    def __str__(self):
+        s = self.__unicode__()
+        return s if six.PY3 else s.encode('utf-8')
+
     def __unicode__(self):
         if self._undefined_hint is None:
             if self._undefined_obj is missing:
index b9b17162bf696d473150d90ec86c07c7f6037e45..b8802501ed960e878e72ed94d0c800ad938eeaec 100644 (file)
@@ -13,6 +13,7 @@
     :license: BSD.
 """
 import operator
+import six
 from jinja2.environment import Environment
 from jinja2.exceptions import SecurityError
 from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \
@@ -299,7 +300,7 @@ class SandboxedEnvironment(Environment):
         try:
             return obj[argument]
         except (TypeError, LookupError):
-            if isinstance(argument, basestring):
+            if isinstance(argument, six.string_types):
                 try:
                     attr = str(argument)
                 except Exception:
index 74017e51352ea7d245973198cadc83bfe24ada85..140b5bf8276f43c35da5b77a54ddeddc9f099d73 100644 (file)
@@ -87,7 +87,7 @@ def test_upper(value):
 
 def test_string(value):
     """Return true if the object is a string."""
-    return isinstance(value, basestring)
+    return isinstance(value, six.string_types)
 
 
 def test_mapping(value):
@@ -100,7 +100,7 @@ def test_mapping(value):
 
 def test_number(value):
     """Return true if the variable is a number."""
-    return isinstance(value, (int, long, float, complex))
+    return isinstance(value, (int, float, complex))
 
 
 def test_sequence(value):
index 65251a544196fd4f5ccf1688bfacabe318e9e64d..29f78b1bc6d7eb21c5d3cdfabc9dbd077142fb27 100644 (file)
@@ -17,15 +17,8 @@ from jinja2 import Environment, DictLoader, contextfunction, nodes
 from jinja2.exceptions import TemplateAssertionError
 from jinja2.ext import Extension
 from jinja2.lexer import Token, count_newlines
-from jinja2.utils import next
 import six
-
-# 2.x / 3.x
-try:
-    from io import BytesIO
-except ImportError:
-    from StringIO import StringIO as BytesIO
-
+from six import BytesIO
 
 importable_object = 23
 
@@ -116,7 +109,7 @@ class TestExtension(Extension):
             self.attr('ext_attr'),
             nodes.ImportedName(__name__ + '.importable_object'),
             nodes.ContextReference()
-        ])]).set_lineno(next(parser.stream).lineno)
+        ])]).set_lineno(six.advance_iterator(parser.stream).lineno)
 
     def _dump(self, sandboxed, ext_attr, imported_object, context):
         return '%s|%s|%s|%s' % (
@@ -433,7 +426,7 @@ class AutoEscapeTestCase(JinjaTestCase):
         '''
         tmpl = env.from_string(tmplsource)
         assert tmpl.render(val=True).split()[0] == 'Markup'
-        assert tmpl.render(val=False).split()[0] == unicode.__name__
+        assert tmpl.render(val=False).split()[0] == six.text_type.__name__
 
         # looking at the source we should see <testing> there in raw
         # (and then escaped as well)
index cd954636a7750abec120367157851ad34fbe5f4b..e74881d4a3f6cfbca3e537b001b7ea9b1fc977e9 100644 (file)
@@ -13,8 +13,7 @@ from jinja2.testsuite import JinjaTestCase
 
 from jinja2 import Markup, Environment
 import six
-from six.moves import map
-from six.moves import zip
+from six.moves import map, zip
 
 env = Environment()
 
@@ -301,6 +300,7 @@ class FilterTestCase(JinjaTestCase):
                 self.value = value
             def __unicode__(self):
                 return six.text_type(self.value)
+            __str__ = __unicode__
         tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''')
         assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234'
 
index e162463ec3eee5e0a29fefbd9096f64d3a6c4d3c..e50b4f4884b945e57f0bb6afed0f72a5bb825611 100644 (file)
@@ -15,6 +15,7 @@ from jinja2.testsuite import JinjaTestCase
 
 from jinja2 import Environment, Template, TemplateSyntaxError, \
      UndefinedError, nodes
+from jinja2.lexer import Token, TokenStream, TOKEN_EOF, TOKEN_BLOCK_BEGIN, TOKEN_BLOCK_END
 import six
 
 env = Environment()
@@ -28,6 +29,30 @@ else:
     jinja_string_repr = repr
 
 
+class TokenStreamTestCase(JinjaTestCase):
+    test_tokens = [Token(1, TOKEN_BLOCK_BEGIN, ''),
+                   Token(2, TOKEN_BLOCK_END, ''),
+                  ]
+
+    def test_simple(self):
+        ts = TokenStream(self.test_tokens, "foo", "bar")
+        assert ts.current.type is TOKEN_BLOCK_BEGIN
+        assert bool(ts)
+        assert not bool(ts.eos)
+        six.advance_iterator(ts)
+        assert ts.current.type is TOKEN_BLOCK_END
+        assert bool(ts)
+        assert not bool(ts.eos)
+        six.advance_iterator(ts)
+        assert ts.current.type is TOKEN_EOF
+        assert not bool(ts)
+        assert bool(ts.eos)
+
+    def test_iter(self):
+        token_types = [t.type for t in TokenStream(self.test_tokens, "foo", "bar")]
+        assert token_types == ['block_begin', 'block_end', ]
+
+
 class LexerTestCase(JinjaTestCase):
 
     def test_raw1(self):
@@ -382,6 +407,7 @@ class SyntaxTestCase(JinjaTestCase):
 
 def suite():
     suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TokenStreamTestCase))
     suite.addTest(unittest.makeSuite(LexerTestCase))
     suite.addTest(unittest.makeSuite(ParserTestCase))
     suite.addTest(unittest.makeSuite(SyntaxTestCase))
index 5c3633f5cdfdccc48b2dbe53908b5ac43e7a0ff1..bac4d60e4f4d2fcc0214d3b35aa9dafce3716bc2 100644 (file)
@@ -14,6 +14,7 @@ from jinja2.testsuite import JinjaTestCase
 
 from jinja2 import Template, Environment, DictLoader, TemplateSyntaxError, \
      TemplateNotFound, PrefixLoader
+import six
 from six.moves import map
 from six.moves import zip
 
@@ -120,7 +121,7 @@ class BugTestCase(JinjaTestCase):
 
         ''')
 
-        assert tmpl.render().split() == map(unicode, list(range(1, 11))) * 5
+        assert tmpl.render().split() == [six.text_type(x) for x in range(1, 11)] * 5
 
     def test_weird_inline_comment(self):
         env = Environment(line_statement_prefix='%')
index 121a008b2e7b25adf3761304650162ca4f3b4220..ca0968bf41702933b7f9b9e70d4a568b3fba7b8f 100644 (file)
@@ -12,6 +12,7 @@ import re
 import sys
 import errno
 import six
+from six.moves import map
 try:
     from urllib.parse import quote_from_bytes as url_quote
 except ImportError:
@@ -19,16 +20,17 @@ except ImportError:
 try:
     from thread import allocate_lock
 except ImportError:
-    from dummy_thread import allocate_lock
+    try:
+        from _thread import allocate_lock  # py 3
+    except ImportError:
+        from dummy_thread import allocate_lock
 from collections import deque
-from itertools import imap
-
 
 _word_split_re = re.compile(r'(\s+)')
 _punctuation_re = re.compile(
     '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
-        '|'.join(imap(re.escape, ('(', '<', '&lt;'))),
-        '|'.join(imap(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
+        '|'.join(map(re.escape, ('(', '<', '&lt;'))),
+        '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
     )
 )
 _simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
@@ -62,21 +64,12 @@ except TypeError as _error:
                 # this hack is needed so that the current frame
                 # does not show up in the traceback.
                 exc_type, exc_value, tb = sys.exc_info()
-                raise exc_type, exc_value, tb.tb_next
+                six.reraise(exc_type, exc_value, tb.tb_next)
     else:
         concat = _concat
     del _test_gen_bug, _error
 
 
-# for python 2.x we create ourselves a next() function that does the
-# basics without exception catching.
-try:
-    next = next
-except NameError:
-    def next(x):
-        return six.advance_iterator(x)
-
-
 # if this python version is unable to deal with unicode filenames
 # when passed to encode we let this function encode it properly.
 # This is used in a couple of places.  As far as Jinja is concerned
@@ -363,9 +356,9 @@ def unicode_urlencode(obj, charset='utf-8'):
     If non strings are provided they are converted to their unicode
     representation first.
     """
-    if not isinstance(obj, basestring):
+    if not isinstance(obj, six.string_types):
         obj = six.text_type(obj)
-    if isinstance(obj, unicode):
+    if isinstance(obj, six.text_type):
         obj = obj.encode(charset)
     return six.text_type(url_quote(obj))
 
@@ -563,7 +556,7 @@ except ImportError:
     pass
 
 
-class Cycler(object):
+class Cycler(six.Iterator):
     """A cycle helper for templates."""
 
     def __init__(self, *items):
@@ -581,7 +574,7 @@ class Cycler(object):
         """Returns the current item."""
         return self.items[self.pos]
 
-    def next(self):
+    def __next__(self):
         """Goes one item ahead and returns it."""
         rv = self.current
         self.pos = (self.pos + 1) % len(self.items)
index 414795620a176ddcbe342103ebc7516dce8c5566..3551ac30c1a61030bccd6995ef1e507c20e30cbf 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -48,14 +48,6 @@ debugsupport = Feature(
 )
 
 
-# tell distribute to use 2to3 with our own fixers.
-extra = {}
-if sys.version_info >= (3, 0):
-    extra.update(
-        use_2to3=True,
-        use_2to3_fixers=['custom_fixers']
-    )
-
 # ignore the old '--with-speedups' flag
 try:
     speedups_pos = sys.argv.index('--with-speedups')
@@ -105,6 +97,5 @@ setup(
     [babel.extractors]
     jinja2 = jinja2.ext:babel_extract[i18n]
     """,
-    features={'debugsupport': debugsupport},
-    **extra
+    features={'debugsupport': debugsupport}
 )