From: Thomas Waldmann Date: Fri, 17 May 2013 22:06:22 +0000 (+0200) Subject: python 3 port: manual fixes, remove 2to3 from setup.py, remove fixers X-Git-Tag: 2.7~88 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7d29562ff9b62b0dd0363624b763361b4c04cc23;p=thirdparty%2Fjinja.git python 3 port: manual fixes, remove 2to3 from setup.py, remove fixers --- diff --git a/custom_fixers/__init__.py b/custom_fixers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/custom_fixers/fix_alt_unicode.py b/custom_fixers/fix_alt_unicode.py deleted file mode 100644 index 96a81c16..00000000 --- a/custom_fixers/fix_alt_unicode.py +++ /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 index fd0ea688..00000000 --- a/custom_fixers/fix_broken_reraising.py +++ /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 index 5d35e505..00000000 --- a/custom_fixers/fix_xrange2.py +++ /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)) diff --git a/jinja2/_markupsafe/__init__.py b/jinja2/_markupsafe/__init__.py index 6aae11a4..a353ff3e 100644 --- a/jinja2/_markupsafe/__init__.py +++ b/jinja2/_markupsafe/__init__.py @@ -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 diff --git a/jinja2/_markupsafe/_native.py b/jinja2/_markupsafe/_native.py index 97065bb0..389be74d 100644 --- a/jinja2/_markupsafe/_native.py +++ b/jinja2/_markupsafe/_native.py @@ -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 diff --git a/jinja2/bccache.py b/jinja2/bccache.py index 0b0ccad1..7c911880 100644 --- a/jinja2/bccache.py +++ b/jinja2/bccache.py @@ -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 diff --git a/jinja2/compiler.py b/jinja2/compiler.py index 35f7d028..4ee39f89 100644 --- a/jinja2/compiler.py +++ b/jinja2/compiler.py @@ -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({') diff --git a/jinja2/debug.py b/jinja2/debug.py index c653e366..55c12fe6 100644 --- a/jinja2/debug.py +++ b/jinja2/debug.py @@ -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) diff --git a/jinja2/defaults.py b/jinja2/defaults.py index d2d45443..97b17ee7 100644 --- a/jinja2/defaults.py +++ b/jinja2/defaults.py @@ -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 diff --git a/jinja2/environment.py b/jinja2/environment.py index 71f022f3..a8149c71 100644 --- a/jinja2/environment.py +++ b/jinja2/environment.py @@ -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() diff --git a/jinja2/exceptions.py b/jinja2/exceptions.py index 90025210..f38d3474 100644 --- a/jinja2/exceptions.py +++ b/jinja2/exceptions.py @@ -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: diff --git a/jinja2/ext.py b/jinja2/ext.py index 984a4d95..0652a340 100644 --- a/jinja2/ext.py +++ b/jinja2/ext.py @@ -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) diff --git a/jinja2/filters.py b/jinja2/filters.py index 43387aeb..d137fc57 100644 --- a/jinja2/filters.py +++ b/jinja2/filters.py @@ -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) diff --git a/jinja2/lexer.py b/jinja2/lexer.py index 5d24718f..d56bc678 100644 --- a/jinja2/lexer.py +++ b/jinja2/lexer.py @@ -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'(? there in raw # (and then escaped as well) diff --git a/jinja2/testsuite/filters.py b/jinja2/testsuite/filters.py index cd954636..e74881d4 100644 --- a/jinja2/testsuite/filters.py +++ b/jinja2/testsuite/filters.py @@ -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' diff --git a/jinja2/testsuite/lexnparse.py b/jinja2/testsuite/lexnparse.py index e162463e..e50b4f48 100644 --- a/jinja2/testsuite/lexnparse.py +++ b/jinja2/testsuite/lexnparse.py @@ -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)) diff --git a/jinja2/testsuite/regression.py b/jinja2/testsuite/regression.py index 5c3633f5..bac4d60e 100644 --- a/jinja2/testsuite/regression.py +++ b/jinja2/testsuite/regression.py @@ -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='%') diff --git a/jinja2/utils.py b/jinja2/utils.py index 121a008b..ca0968bf 100644 --- a/jinja2/utils.py +++ b/jinja2/utils.py @@ -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(?:%s)*)(?P.*?)(?P(?:%s)*)$' % ( - '|'.join(imap(re.escape, ('(', '<', '<'))), - '|'.join(imap(re.escape, ('.', ',', ')', '>', '\n', '>'))) + '|'.join(map(re.escape, ('(', '<', '<'))), + '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '>'))) ) ) _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) diff --git a/setup.py b/setup.py index 41479562..3551ac30 100644 --- 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} )