diff options
author | Armin Ronacher <armin.ronacher@active-4.com> | 2013-05-19 14:16:13 +0100 |
---|---|---|
committer | Armin Ronacher <armin.ronacher@active-4.com> | 2013-05-19 14:16:13 +0100 |
commit | e909867721a000beaec6340d17ecc39eac6fad4e (patch) | |
tree | c1d9e48fa658c6b0f006b1635d0644b62d83d0b2 | |
parent | cd7bf5b00f77adc0f875efb9d945b9b42271f53a (diff) | |
download | jinja2-e909867721a000beaec6340d17ecc39eac6fad4e.tar.gz |
Moved all six usages (ignoring testsuite) into jinja2._compat
-rw-r--r-- | jinja2/_compat.py | 52 | ||||
-rw-r--r-- | jinja2/bccache.py | 8 | ||||
-rw-r--r-- | jinja2/compiler.py | 30 | ||||
-rw-r--r-- | jinja2/debug.py | 18 | ||||
-rw-r--r-- | jinja2/environment.py | 38 | ||||
-rw-r--r-- | jinja2/exceptions.py | 18 | ||||
-rw-r--r-- | jinja2/ext.py | 11 | ||||
-rw-r--r-- | jinja2/filters.py | 40 | ||||
-rw-r--r-- | jinja2/lexer.py | 15 | ||||
-rw-r--r-- | jinja2/loaders.py | 15 | ||||
-rw-r--r-- | jinja2/meta.py | 9 | ||||
-rw-r--r-- | jinja2/nodes.py | 15 | ||||
-rw-r--r-- | jinja2/runtime.py | 43 | ||||
-rw-r--r-- | jinja2/sandbox.py | 15 | ||||
-rw-r--r-- | jinja2/tests.py | 19 | ||||
-rw-r--r-- | jinja2/utils.py | 36 |
16 files changed, 199 insertions, 183 deletions
diff --git a/jinja2/_compat.py b/jinja2/_compat.py index 8c1963c..f10ef65 100644 --- a/jinja2/_compat.py +++ b/jinja2/_compat.py @@ -12,6 +12,9 @@ :license: BSD, see LICENSE for details. """ import six +import sys + +PY3 = six.PY3 # https://bitbucket.org/gutworth/six/issue/25/add-unichr try: @@ -22,3 +25,52 @@ except NameError: range_type = six.moves.xrange next = six.advance_iterator imap = six.moves.map +izip = six.moves.zip +text_type = six.text_type +string_types = six.string_types + +iteritems = six.iteritems + +if six.PY3: + from io import BytesIO, StringIO + NativeStringIO = StringIO +else: + from cStringIO import StringIO as BytesIO + from StringIO import StringIO + NativeStringIO = BytesIO + +try: + import cPickle as pickle +except ImportError: + import pickle + +ifilter = six.moves.filter +reraise = six.reraise +Iterator = six.Iterator +with_metaclass = six.with_metaclass + +try: + from collections import Mapping as mapping_types +except ImportError: + import UserDict + mapping_types = (UserDict.UserDict, UserDict.DictMixin, dict) + + +# common types. These do exist in the special types module too which however +# does not exist in IronPython out of the box. Also that way we don't have +# to deal with implementation specific stuff here +class _C(object): + def method(self): pass +def _func(): + yield None +function_type = type(_func) +generator_type = type(_func()) +method_type = type(_C().method) +code_type = type(_C.method.__code__) +try: + raise TypeError() +except TypeError: + _tb = sys.exc_info()[2] + traceback_type = type(_tb) + frame_type = type(_tb.tb_frame) +del _C, _tb, _func diff --git a/jinja2/bccache.py b/jinja2/bccache.py index f022918..dbfc3c2 100644 --- a/jinja2/bccache.py +++ b/jinja2/bccache.py @@ -18,14 +18,10 @@ from os import path, listdir import sys import marshal import tempfile -from six.moves import cPickle as pickle -from six import BytesIO import fnmatch -try: - from hashlib import sha1 -except ImportError: - from sha import new as sha1 +from hashlib import sha1 from jinja2.utils import open_if_exists +from jinja2._compat import BytesIO, pickle # marshal works better on 3.x, one hack less required diff --git a/jinja2/compiler.py b/jinja2/compiler.py index ce8e06d..4c7a52d 100644 --- a/jinja2/compiler.py +++ b/jinja2/compiler.py @@ -8,8 +8,6 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import six - from itertools import chain from copy import deepcopy from jinja2 import nodes @@ -17,8 +15,8 @@ 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 -from jinja2._compat import range_type, next -from six.moves import cStringIO as StringIO, map +from jinja2._compat import range_type, next, text_type, string_types, \ + iteritems, NativeStringIO, imap operators = { @@ -69,7 +67,7 @@ def has_safe_repr(value): if value is None or value is NotImplemented or value is Ellipsis: return True if isinstance(value, (bool, int, float, complex, range_type, - Markup) + six.string_types): + Markup) + string_types): return True if isinstance(value, (tuple, list, set, frozenset)): for item in value: @@ -77,7 +75,7 @@ def has_safe_repr(value): return False return True elif isinstance(value, dict): - for key, value in six.iteritems(value): + for key, value in iteritems(value): if not has_safe_repr(key): return False if not has_safe_repr(value): @@ -367,7 +365,7 @@ class CodeGenerator(NodeVisitor): def __init__(self, environment, name, filename, stream=None, defer_init=False): if stream is None: - stream = StringIO() + stream = NativeStringIO() self.environment = environment self.name = name self.filename = filename @@ -541,7 +539,7 @@ class CodeGenerator(NodeVisitor): self.write(', ') self.visit(kwarg, frame) if extra_kwargs is not None: - for key, value in six.iteritems(extra_kwargs): + for key, value in iteritems(extra_kwargs): self.write(', %s=%s' % (key, value)) if node.dyn_args: self.write(', *') @@ -557,7 +555,7 @@ class CodeGenerator(NodeVisitor): self.visit(kwarg.value, frame) self.write(', ') if extra_kwargs is not None: - for key, value in six.iteritems(extra_kwargs): + for key, value in iteritems(extra_kwargs): self.write('%r: %s, ' % (key, value)) if node.dyn_kwargs is not None: self.write('}, **') @@ -624,7 +622,7 @@ class CodeGenerator(NodeVisitor): def pop_scope(self, aliases, frame): """Restore all aliases and delete unused variables.""" - for name, alias in six.iteritems(aliases): + for name, alias in iteritems(aliases): self.writeline('l_%s = %s' % (name, alias)) to_delete = set() for name in frame.identifiers.declared_locally: @@ -826,7 +824,7 @@ class CodeGenerator(NodeVisitor): self.outdent(2 + (not self.has_known_extends)) # at this point we now have the blocks collected and can visit them too. - for name, block in six.iteritems(self.blocks): + for name, block in iteritems(self.blocks): block_frame = Frame(eval_ctx) block_frame.inspect(block.body) block_frame.block = name @@ -930,7 +928,7 @@ class CodeGenerator(NodeVisitor): func_name = 'get_or_select_template' if isinstance(node.template, nodes.Const): - if isinstance(node.template.value, six.string_types): + if isinstance(node.template.value, string_types): func_name = 'get_template' elif isinstance(node.template.value, (tuple, list)): func_name = 'select_template' @@ -1039,7 +1037,7 @@ class CodeGenerator(NodeVisitor): discarded_names[0]) else: self.writeline('context.exported_vars.difference_' - 'update((%s))' % ', '.join(map(repr, discarded_names))) + 'update((%s))' % ', '.join(imap(repr, discarded_names))) def visit_For(self, node, frame): # when calculating the nodes for the inner frame we have to exclude @@ -1224,9 +1222,9 @@ class CodeGenerator(NodeVisitor): return if self.environment.finalize: - finalize = lambda x: six.text_type(self.environment.finalize(x)) + finalize = lambda x: text_type(self.environment.finalize(x)) else: - finalize = six.text_type + finalize = text_type # if we are inside a frame that requires output checking, we do so outdent_later = False @@ -1375,7 +1373,7 @@ class CodeGenerator(NodeVisitor): public_names[0]) else: self.writeline('context.exported_vars.update((%s))' % - ', '.join(map(repr, public_names))) + ', '.join(imap(repr, public_names))) # -- Expression Visitors diff --git a/jinja2/debug.py b/jinja2/debug.py index 31c25cc..815cc18 100644 --- a/jinja2/debug.py +++ b/jinja2/debug.py @@ -13,9 +13,9 @@ import sys import traceback from types import TracebackType -from jinja2.utils import CodeType, missing, internal_code +from jinja2.utils import missing, internal_code from jinja2.exceptions import TemplateSyntaxError -import six +from jinja2._compat import iteritems, reraise, code_type # on pypy we can take advantage of transparent proxies try: @@ -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: - six.reraise(exc_info[0], exc_info[1], exc_info[2]) + reraise(exc_info[0], exc_info[1], exc_info[2]) return ProcessedTraceback(exc_info[0], exc_info[1], frames) @@ -207,7 +207,7 @@ def fake_exc_info(exc_info, filename, lineno): locals = ctx.get_all() else: locals = {} - for name, value in six.iteritems(real_locals): + for name, value in iteritems(real_locals): if name.startswith('l_') and value is not missing: locals[name[2:]] = value @@ -245,11 +245,11 @@ def fake_exc_info(exc_info, filename, lineno): location = 'block "%s"' % function[6:] else: location = 'template' - code = CodeType(0, code.co_nlocals, code.co_stacksize, - code.co_flags, code.co_code, code.co_consts, - code.co_names, code.co_varnames, filename, - location, code.co_firstlineno, - code.co_lnotab, (), ()) + code = code_type(0, code.co_nlocals, code.co_stacksize, + code.co_flags, code.co_code, code.co_consts, + code.co_names, code.co_varnames, filename, + location, code.co_firstlineno, + code.co_lnotab, (), ()) except: pass diff --git a/jinja2/environment.py b/jinja2/environment.py index 450cac1..ee35b89 100644 --- a/jinja2/environment.py +++ b/jinja2/environment.py @@ -27,9 +27,9 @@ from jinja2.exceptions import TemplateSyntaxError, TemplateNotFound, \ TemplatesNotFound, TemplateRuntimeError from jinja2.utils import import_string, LRUCache, Markup, missing, \ concat, consume, internalcode, _encode_filename -import six +from jinja2._compat import imap, ifilter, string_types, iteritems, \ + text_type, reraise, PY3, Iterator, next from functools import reduce -from six.moves import filter, map # for direct template usage we have up to ten living environments @@ -80,7 +80,7 @@ def load_extensions(environment, extensions): """ result = {} for extension in extensions: - if isinstance(extension, six.string_types): + if isinstance(extension, string_types): extension = import_string(extension) result[extension.identifier] = extension(environment) return result @@ -315,7 +315,7 @@ class Environment(object): yet. This is used by :ref:`extensions <writing-extensions>` to register callbacks and configuration values without breaking inheritance. """ - for key, value in six.iteritems(attributes): + for key, value in iteritems(attributes): if not hasattr(self, key): setattr(self, key, value) @@ -347,7 +347,7 @@ class Environment(object): rv.overlayed = True rv.linked_to = self - for key, value in six.iteritems(args): + for key, value in iteritems(args): if value is not missing: setattr(rv, key, value) @@ -357,7 +357,7 @@ class Environment(object): rv.cache = copy_cache(self.cache) rv.extensions = {} - for key, value in six.iteritems(self.extensions): + for key, value in iteritems(self.extensions): rv.extensions[key] = value.bind(rv) if extensions is not missing: rv.extensions.update(load_extensions(rv, extensions)) @@ -376,7 +376,7 @@ class Environment(object): try: return obj[argument] except (TypeError, LookupError): - if isinstance(argument, six.string_types): + if isinstance(argument, string_types): try: attr = str(argument) except Exception: @@ -467,7 +467,7 @@ class Environment(object): of the extensions to be applied you have to filter source through the :meth:`preprocess` method. """ - source = six.text_type(source) + source = text_type(source) try: return self.lexer.tokeniter(source, name, filename) except TemplateSyntaxError: @@ -480,7 +480,7 @@ class Environment(object): because there you usually only want the actual source tokenized. """ return reduce(lambda s, e: e.preprocess(s, name, filename), - self.iter_extensions(), six.text_type(source)) + self.iter_extensions(), text_type(source)) def _tokenize(self, source, name, filename=None, state=None): """Called by the parser to do the preprocessing and filtering @@ -534,7 +534,7 @@ class Environment(object): """ source_hint = None try: - if isinstance(source, six.string_types): + if isinstance(source, string_types): source_hint = source source = self._parse(source, name, filename) if self.optimized: @@ -708,7 +708,7 @@ class Environment(object): filter_func = lambda x: '.' in x and \ x.rsplit('.', 1)[1] in extensions if filter_func is not None: - x = filter(filter_func, x) + x = ifilter(filter_func, x) return x def handle_exception(self, exc_info=None, rendered=False, source_hint=None): @@ -731,7 +731,7 @@ class Environment(object): if self.exception_handler is not None: self.exception_handler(traceback) exc_type, exc_value, tb = traceback.standard_exc_info - six.reraise(exc_type, exc_value, tb) + reraise(exc_type, exc_value, tb) def join_path(self, template, parent): """Join a template with the parent. By default all the lookups are @@ -818,7 +818,7 @@ class Environment(object): .. versionadded:: 2.3 """ - if isinstance(template_name_or_list, six.string_types): + if isinstance(template_name_or_list, string_types): return self.get_template(template_name_or_list, parent, globals) elif isinstance(template_name_or_list, Template): return template_name_or_list @@ -1040,7 +1040,7 @@ class Template(object): @property def debug_info(self): """The debug info mapping.""" - return [tuple(map(int, x.split('='))) for x in + return [tuple(imap(int, x.split('='))) for x in self._debug_info.split('&')] def __repr__(self): @@ -1067,7 +1067,7 @@ class TemplateModule(object): def __str__(self): s = self.__unicode__() - return s if six.PY3 else s.encode('utf-8') + return s if PY3 else s.encode('utf-8') def __unicode__(self): return concat(self._body_stream) @@ -1099,7 +1099,7 @@ class TemplateExpression(object): return rv -class TemplateStream(six.Iterator): +class TemplateStream(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 @@ -1124,7 +1124,7 @@ class TemplateStream(six.Iterator): Template('Hello {{ name }}!').stream(name='foo').dump('hello.html') """ close = False - if isinstance(fp, six.string_types): + if isinstance(fp, string_types): fp = open(fp, encoding is None and 'w' or 'wb') close = True try: @@ -1143,7 +1143,7 @@ class TemplateStream(six.Iterator): def disable_buffering(self): """Disable the output buffering.""" - self._next = lambda: six.next(self._gen) + self._next = lambda: next(self._gen) self.buffered = False def enable_buffering(self, size=5): @@ -1171,7 +1171,7 @@ class TemplateStream(six.Iterator): c_size = 0 self.buffered = True - self._next = lambda: six.next(generator(lambda: six.next(self._gen))) + self._next = lambda: next(generator(lambda: next(self._gen))) def __iter__(self): return self diff --git a/jinja2/exceptions.py b/jinja2/exceptions.py index 9fe698b..0075be0 100644 --- a/jinja2/exceptions.py +++ b/jinja2/exceptions.py @@ -9,8 +9,7 @@ :license: BSD, see LICENSE for more details. """ import sys -import six -from six.moves import map +from jinja2._compat import imap, text_type, PY3 class TemplateError(Exception): @@ -19,7 +18,7 @@ class TemplateError(Exception): if sys.version_info[0] < 3: def __init__(self, message=None): if message is not None: - message = six.text_type(message).encode('utf-8') + message = text_type(message).encode('utf-8') Exception.__init__(self, message) @property @@ -75,7 +74,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(six.text_type, names)) + u', '.join(imap(text_type, names)) TemplateNotFound.__init__(self, names and names[-1] or None, message) self.templates = list(names) @@ -94,10 +93,6 @@ class TemplateSyntaxError(TemplateError): # function translated the syntax error into a new traceback self.translated = False - def __str__(self): - s = self.__unicode__() - return s if six.PY3 else s.encode('utf-8') - def __unicode__(self): # for translated errors we only return the message if self.translated: @@ -121,6 +116,13 @@ class TemplateSyntaxError(TemplateError): return u'\n'.join(lines) + if PY3: + __str__ = __unicode__ + del __unicode__ + else: + def __str__(self): + return self.__unicode__().encode('utf-8') + class TemplateAssertionError(TemplateSyntaxError): """Like a template syntax error, but covers cases where something in the diff --git a/jinja2/ext.py b/jinja2/ext.py index 8ded3d1..a88c088 100644 --- a/jinja2/ext.py +++ b/jinja2/ext.py @@ -20,8 +20,7 @@ from jinja2.environment import Environment from jinja2.runtime import concat from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError from jinja2.utils import contextfunction, import_string, Markup -from jinja2._compat import next -import six +from jinja2._compat import next, with_metaclass, string_types, iteritems # the only real useful gettext functions for a Jinja template. Note @@ -39,7 +38,7 @@ class ExtensionRegistry(type): return rv -class Extension(six.with_metaclass(ExtensionRegistry, object)): +class Extension(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 @@ -210,7 +209,7 @@ class InternationalizationExtension(Extension): self.environment.globals.pop(key, None) def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS): - if isinstance(source, six.string_types): + if isinstance(source, string_types): source = self.environment.parse(source) return extract_from_ast(source, gettext_functions) @@ -369,7 +368,7 @@ class InternationalizationExtension(Extension): # enough to handle the variable expansion and autoescape # handling itself if self.environment.newstyle_gettext: - for key, value in six.iteritems(variables): + for key, value in iteritems(variables): # the function adds that later anyways in case num was # called num, so just skip it. if num_called_num and key == 'num': @@ -491,7 +490,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, six.string_types): + isinstance(arg.value, string_types): strings.append(arg.value) else: strings.append(None) diff --git a/jinja2/filters.py b/jinja2/filters.py index f0fbb38..2f6ffd0 100644 --- a/jinja2/filters.py +++ b/jinja2/filters.py @@ -10,7 +10,6 @@ """ import re import math -import six from random import choice from operator import itemgetter @@ -19,8 +18,7 @@ from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \ unicode_urlencode from jinja2.runtime import Undefined from jinja2.exceptions import FilterArgumentError -from jinja2._compat import next -from six.moves import map +from jinja2._compat import next, imap, string_types, text_type, iteritems _word_re = re.compile(r'\w+(?u)') @@ -58,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, six.string_types) or '.' not in attribute: + if not isinstance(attribute, string_types) or '.' not in attribute: return lambda x: environment.getitem(x, attribute) attribute = attribute.split('.') def attrgetter(item): @@ -72,7 +70,7 @@ def do_forceescape(value): """Enforce HTML escaping. This will probably double escape variables.""" if hasattr(value, '__html__'): value = value.__html__() - return escape(six.text_type(value)) + return escape(text_type(value)) def do_urlencode(value): @@ -83,8 +81,8 @@ def do_urlencode(value): """ itemiter = None if isinstance(value, dict): - itemiter = six.iteritems(value) - elif not isinstance(value, six.string_types): + itemiter = iteritems(value) + elif not isinstance(value, string_types): try: itemiter = iter(value) except TypeError: @@ -114,7 +112,7 @@ def do_replace(eval_ctx, s, old, new, count=None): if count is None: count = -1 if not eval_ctx.autoescape: - return six.text_type(s).replace(six.text_type(old), six.text_type(new), count) + return text_type(s).replace(text_type(old), text_type(new), count) if hasattr(old, '__html__') or hasattr(new, '__html__') and \ not hasattr(s, '__html__'): s = escape(s) @@ -159,7 +157,7 @@ def do_xmlattr(_eval_ctx, d, autospace=True): """ rv = u' '.join( u'%s="%s"' % (escape(key), escape(value)) - for key, value in six.iteritems(d) + for key, value in iteritems(d) if value is not None and not isinstance(value, Undefined) ) if autospace and rv: @@ -214,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, six.string_types) and not case_sensitive: + if isinstance(value, string_types) and not case_sensitive: value = value.lower() return value @@ -251,7 +249,7 @@ def do_sort(environment, value, reverse=False, case_sensitive=False, """ if not case_sensitive: def sort_func(item): - if isinstance(item, six.string_types): + if isinstance(item, string_types): item = item.lower() return item else: @@ -309,11 +307,11 @@ def do_join(eval_ctx, value, d=u'', attribute=None): The `attribute` parameter was added. """ if attribute is not None: - value = map(make_attrgetter(eval_ctx.environment, attribute), value) + value = imap(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(map(six.text_type, value)) + return text_type(d).join(imap(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 @@ -324,20 +322,20 @@ def do_join(eval_ctx, value, d=u'', attribute=None): if hasattr(item, '__html__'): do_escape = True else: - value[idx] = six.text_type(item) + value[idx] = text_type(item) if do_escape: d = escape(d) else: - d = six.text_type(d) + d = text_type(d) return d.join(value) # no html involved, to normal joining - return soft_unicode(d).join(map(soft_unicode, value)) + return soft_unicode(d).join(imap(soft_unicode, value)) def do_center(value, width=80): """Centers the value in a field of a given width.""" - return six.text_type(value).center(width) + return text_type(value).center(width) @environmentfilter @@ -552,7 +550,7 @@ def do_striptags(value): """ if hasattr(value, '__html__'): value = value.__html__() - return Markup(six.text_type(value)).striptags() + return Markup(text_type(value)).striptags() def do_slice(value, slices, fill_with=None): @@ -727,7 +725,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 = map(make_attrgetter(environment, attribute), iterable) + iterable = imap(make_attrgetter(environment, attribute), iterable) return sum(iterable, start) @@ -747,14 +745,14 @@ def do_mark_safe(value): def do_mark_unsafe(value): """Mark a value as unsafe. This is the reverse operation for :func:`safe`.""" - return six.text_type(value) + return text_type(value) def do_reverse(value): """Reverse the object or return an iterator the iterates over it the other way round. """ - if isinstance(value, six.string_types): + if isinstance(value, string_types): return value[::-1] try: return reversed(value) diff --git a/jinja2/lexer.py b/jinja2/lexer.py index 07cf5c6..87e0920 100644 --- a/jinja2/lexer.py +++ b/jinja2/lexer.py @@ -15,13 +15,12 @@ :license: BSD, see LICENSE for more details. """ import re -import six from operator import itemgetter from collections import deque from jinja2.exceptions import TemplateSyntaxError from jinja2.utils import LRUCache -from jinja2._compat import next +from jinja2._compat import next, iteritems, Iterator, text_type # cache for the lexers. Exists in order to be able to have multiple @@ -135,7 +134,7 @@ operators = { ';': TOKEN_SEMICOLON } -reverse_operators = dict([(v, k) for k, v in six.iteritems(operators)]) +reverse_operators = dict([(v, k) for k, v in iteritems(operators)]) assert len(operators) == len(reverse_operators), 'operators dropped' operator_re = re.compile('(%s)' % '|'.join(re.escape(x) for x in sorted(operators, key=lambda x: -len(x)))) @@ -271,7 +270,7 @@ class Token(tuple): ) -class TokenStreamIterator(six.Iterator): +class TokenStreamIterator(Iterator): """The iterator for tokenstreams. Iterate over the stream until the eof token is reached. """ @@ -291,7 +290,7 @@ class TokenStreamIterator(six.Iterator): return token -class TokenStream(six.Iterator): +class TokenStream(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`. @@ -598,7 +597,7 @@ class Lexer(object): """This method tokenizes the text and returns the tokens in a generator. Use this method if you just want to tokenize a template. """ - source = six.text_type(source) + source = text_type(source) lines = source.splitlines() if self.keep_trailing_newline and source: for newline in ('\r\n', '\r', '\n'): @@ -646,7 +645,7 @@ class Lexer(object): # yield for the current token the first named # group that matched elif token == '#bygroup': - for key, value in six.iteritems(m.groupdict()): + for key, value in iteritems(m.groupdict()): if value is not None: yield lineno, key, value lineno += value.count('\n') @@ -703,7 +702,7 @@ class Lexer(object): stack.pop() # resolve the new state by group checking elif new_state == '#bygroup': - for key, value in six.iteritems(m.groupdict()): + for key, value in iteritems(m.groupdict()): if value is not None: stack.append(key) break diff --git a/jinja2/loaders.py b/jinja2/loaders.py index f8e4f99..a9a2625 100644 --- a/jinja2/loaders.py +++ b/jinja2/loaders.py @@ -13,13 +13,10 @@ import sys import weakref from types import ModuleType from os import path -import six -try: - from hashlib import sha1 -except ImportError: - from sha import new as sha1 +from hashlib import sha1 from jinja2.exceptions import TemplateNotFound from jinja2.utils import open_if_exists, internalcode +from jinja2._compat import string_types, iteritems def split_template_path(template): @@ -154,7 +151,7 @@ class FileSystemLoader(BaseLoader): """ def __init__(self, searchpath, encoding='utf-8'): - if isinstance(searchpath, six.string_types): + if isinstance(searchpath, string_types): searchpath = [searchpath] self.searchpath = list(searchpath) self.encoding = encoding @@ -307,7 +304,7 @@ class FunctionLoader(BaseLoader): rv = self.load_func(template) if rv is None: raise TemplateNotFound(template) - elif isinstance(rv, six.string_types): + elif isinstance(rv, string_types): return rv, None, None return rv @@ -360,7 +357,7 @@ class PrefixLoader(BaseLoader): def list_templates(self): result = [] - for prefix, loader in six.iteritems(self.mapping): + for prefix, loader in iteritems(self.mapping): for template in loader.list_templates(): result.append(prefix + self.delimiter + template) return result @@ -432,7 +429,7 @@ class ModuleLoader(BaseLoader): # create a fake module that looks for the templates in the # path given. mod = _TemplateModule(package_name) - if isinstance(path, six.string_types): + if isinstance(path, string_types): path = [path] else: path = list(path) diff --git a/jinja2/meta.py b/jinja2/meta.py index 26ae0b9..3110cff 100644 --- a/jinja2/meta.py +++ b/jinja2/meta.py @@ -11,7 +11,8 @@ """ from jinja2 import nodes from jinja2.compiler import CodeGenerator -import six +from jinja2._compat import string_types + class TrackingCodeGenerator(CodeGenerator): """We abuse the code generator for introspection.""" @@ -77,7 +78,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, six.string_types): + if isinstance(template_name.value, string_types): yield template_name.value # something dynamic in there else: @@ -87,7 +88,7 @@ def find_referenced_templates(ast): yield None continue # constant is a basestring, direct template name - if isinstance(node.template.value, six.string_types): + if isinstance(node.template.value, 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 +96,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, six.string_types): + if isinstance(template_name, string_types): yield template_name # something else we don't care about, we could warn here else: diff --git a/jinja2/nodes.py b/jinja2/nodes.py index e276f7e..26ba348 100644 --- a/jinja2/nodes.py +++ b/jinja2/nodes.py @@ -12,17 +12,16 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import six import operator from collections import deque -from jinja2.utils import Markup, MethodType, FunctionType -from jinja2._compat import next -from six.moves import zip +from jinja2.utils import Markup +from jinja2._compat import next, izip, with_metaclass, text_type, \ + method_type, function_type #: the types we support for context functions -_context_function_types = (FunctionType, MethodType) +_context_function_types = (function_type, method_type) _binop_to_func = { @@ -105,7 +104,7 @@ def get_eval_context(node, ctx): return ctx -class Node(six.with_metaclass(NodeType, object)): +class Node(with_metaclass(NodeType, object)): """Baseclass for all Jinja2 nodes. There are a number of nodes available of different types. There are four major types: @@ -139,7 +138,7 @@ class Node(six.with_metaclass(NodeType, object)): len(self.fields), len(self.fields) != 1 and 's' or '' )) - for name, arg in zip(self.fields, fields): + for name, arg in izip(self.fields, fields): setattr(self, name, arg) for attr in self.attributes: setattr(self, attr, attributes.pop(attr, None)) @@ -690,7 +689,7 @@ class Concat(Expr): def as_const(self, eval_ctx=None): eval_ctx = get_eval_context(self, eval_ctx) - return ''.join(six.text_type(x.as_const(eval_ctx)) for x in self.nodes) + return ''.join(text_type(x.as_const(eval_ctx)) for x in self.nodes) class Compare(Expr): diff --git a/jinja2/runtime.py b/jinja2/runtime.py index f2c4719..489bcca 100644 --- a/jinja2/runtime.py +++ b/jinja2/runtime.py @@ -14,9 +14,8 @@ from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \ internalcode, object_type_repr from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ TemplateNotFound -from jinja2._compat import next -import six -from six.moves import map +from jinja2._compat import next, imap, text_type, iteritems, Iterator, \ + string_types, PY3 # these variables are exported to the template runtime @@ -42,7 +41,7 @@ _last_iteration = object() def markup_join(seq): """Concatenation that escapes if necessary and converts to unicode.""" buf = [] - iterator = map(soft_unicode, seq) + iterator = imap(soft_unicode, seq) for arg in iterator: buf.append(arg) if hasattr(arg, '__html__'): @@ -52,7 +51,7 @@ def markup_join(seq): def unicode_join(seq): """Simple args to unicode conversion and concatenation.""" - return concat(map(six.text_type, seq)) + return concat(imap(text_type, seq)) def new_context(environment, template_name, blocks, vars=None, @@ -69,7 +68,7 @@ def new_context(environment, template_name, blocks, vars=None, # we don't want to modify the dict passed if shared: parent = dict(parent) - for key, value in six.iteritems(locals): + for key, value in iteritems(locals): if key[:2] == 'l_' and value is not missing: parent[key[2:]] = value return Context(environment, parent, template_name, blocks) @@ -125,7 +124,7 @@ class Context(object): # create the initial mapping of blocks. Whenever template inheritance # takes place the runtime will update this mapping with the new blocks # from the template. - self.blocks = dict((k, [v]) for k, v in six.iteritems(blocks)) + self.blocks = dict((k, [v]) for k, v in iteritems(blocks)) def super(self, name, current): """Render a parent block.""" @@ -208,7 +207,7 @@ class Context(object): self.parent, True, None, locals) context.vars.update(self.vars) context.eval_ctx = self.eval_ctx - context.blocks.update((k, list(v)) for k, v in six.iteritems(self.blocks)) + context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) return context def _all(meth): @@ -357,7 +356,7 @@ class LoopContext(object): ) -class LoopContextIterator(six.Iterator): +class LoopContextIterator(Iterator): """The iterator for a loop context.""" __slots__ = ('context',) @@ -472,7 +471,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, six.string_types): + elif not isinstance(self._undefined_name, string_types): hint = '%s has no element %r' % ( object_type_repr(self._undefined_obj), self._undefined_name @@ -499,13 +498,16 @@ class Undefined(object): __float__ = __complex__ = __pow__ = __rpow__ = \ _fail_with_undefined_error - def __str__(self): - s = self.__unicode__() - return s if six.PY3 else s.encode('utf-8') - def __unicode__(self): return u'' + if PY3: + __str__ = __unicode__ + del __unicode__ + else: + def __str__(self): + return self.__unicode__().encode('utf-8') + def __len__(self): return 0 @@ -535,10 +537,6 @@ 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: @@ -549,6 +547,10 @@ class DebugUndefined(Undefined): ) return u'{{ undefined value printed: %s }}' % self._undefined_hint + if PY3: + __str__ = __unicode__ + del __unicode__ + class StrictUndefined(Undefined): """An undefined that barks on print and iteration as well as boolean @@ -570,9 +572,12 @@ class StrictUndefined(Undefined): UndefinedError: 'foo' is undefined """ __slots__ = () - __iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \ + __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \ __ne__ = __bool__ = Undefined._fail_with_undefined_error + if not PY3: + __unicode__ = Undefined._fail_with_undefined_error + # remove remaining slots attributes, after the metaclass did the magic they # are unneeded and irritating as they contain wrong data for the subclasses. diff --git a/jinja2/sandbox.py b/jinja2/sandbox.py index ed145d5..68fc599 100644 --- a/jinja2/sandbox.py +++ b/jinja2/sandbox.py @@ -13,11 +13,10 @@ :license: BSD. """ import operator -import six from jinja2.environment import Environment from jinja2.exceptions import SecurityError -from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \ - FrameType, GeneratorType +from jinja2._compat import string_types, function_type, method_type, \ + traceback_type, code_type, frame_type, generator_type #: maximum number of items a range may produce @@ -125,19 +124,19 @@ def is_internal_attribute(obj, attr): >>> is_internal_attribute(str, "upper") False """ - if isinstance(obj, FunctionType): + if isinstance(obj, function_type): if attr in UNSAFE_FUNCTION_ATTRIBUTES: return True - elif isinstance(obj, MethodType): + elif isinstance(obj, method_type): if attr in UNSAFE_FUNCTION_ATTRIBUTES or \ attr in UNSAFE_METHOD_ATTRIBUTES: return True elif isinstance(obj, type): if attr == 'mro': return True - elif isinstance(obj, (CodeType, TracebackType, FrameType)): + elif isinstance(obj, (code_type, traceback_type, frame_type)): return True - elif isinstance(obj, GeneratorType): + elif isinstance(obj, generator_type): if attr == 'gi_frame': return True return attr.startswith('__') @@ -300,7 +299,7 @@ class SandboxedEnvironment(Environment): try: return obj[argument] except (TypeError, LookupError): - if isinstance(argument, six.string_types): + if isinstance(argument, string_types): try: attr = str(argument) except Exception: diff --git a/jinja2/tests.py b/jinja2/tests.py index 140b5bf..5fff61a 100644 --- a/jinja2/tests.py +++ b/jinja2/tests.py @@ -10,16 +10,7 @@ """ import re from jinja2.runtime import Undefined -import six - -try: - from collections import Mapping as MappingType -except ImportError: - import UserDict - MappingType = (UserDict.UserDict, UserDict.DictMixin, dict) - -# nose, nothing here to test -__test__ = False +from jinja2._compat import text_type, string_types, mapping_types number_re = re.compile(r'^-?\d+(\.\d+)?$') @@ -77,17 +68,17 @@ def test_none(value): def test_lower(value): """Return true if the variable is lowercased.""" - return six.text_type(value).islower() + return text_type(value).islower() def test_upper(value): """Return true if the variable is uppercased.""" - return six.text_type(value).isupper() + return text_type(value).isupper() def test_string(value): """Return true if the object is a string.""" - return isinstance(value, six.string_types) + return isinstance(value, string_types) def test_mapping(value): @@ -95,7 +86,7 @@ def test_mapping(value): .. versionadded:: 2.6 """ - return isinstance(value, MappingType) + return isinstance(value, mapping_types) def test_number(value): diff --git a/jinja2/utils.py b/jinja2/utils.py index 164c583..f3cf10e 100644 --- a/jinja2/utils.py +++ b/jinja2/utils.py @@ -11,8 +11,6 @@ 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: @@ -25,6 +23,8 @@ except ImportError: except ImportError: from dummy_thread import allocate_lock from collections import deque +from jinja2._compat import text_type, string_types, Iterator + _word_split_re = re.compile(r'(\s+)') _punctuation_re = re.compile( @@ -67,26 +67,6 @@ else: from keyword import iskeyword as is_python_keyword -# common types. These do exist in the special types module too which however -# does not exist in IronPython out of the box. Also that way we don't have -# to deal with implementation specific stuff here -class _C(object): - def method(self): pass -def _func(): - yield None -FunctionType = type(_func) -GeneratorType = type(_func()) -MethodType = type(_C().method) -CodeType = type(_C.method.__code__) -try: - raise TypeError() -except TypeError: - _tb = sys.exc_info()[2] - TracebackType = type(_tb) - FrameType = type(_tb.tb_frame) -del _C, _tb, _func - - def contextfunction(f): """This decorator can be used to mark a function or method context callable. A context callable is passed the active :class:`Context` as first argument when @@ -247,7 +227,7 @@ def urlize(text, trim_url_limit=None, nofollow=False): trim_url = lambda x, limit=trim_url_limit: limit is not None \ and (x[:limit] + (len(x) >=limit and '...' or '')) or x - words = _word_split_re.split(six.text_type(escape(text))) + words = _word_split_re.split(text_type(escape(text))) nofollow_attr = nofollow and ' rel="nofollow"' or '' for i, word in enumerate(words): match = _punctuation_re.match(word) @@ -334,11 +314,11 @@ def unicode_urlencode(obj, charset='utf-8'): If non strings are provided they are converted to their unicode representation first. """ - if not isinstance(obj, six.string_types): - obj = six.text_type(obj) - if isinstance(obj, six.text_type): + if not isinstance(obj, string_types): + obj = text_type(obj) + if isinstance(obj, text_type): obj = obj.encode(charset) - return six.text_type(url_quote(obj)) + return text_type(url_quote(obj)) class LRUCache(object): @@ -526,7 +506,7 @@ except ImportError: pass -class Cycler(six.Iterator): +class Cycler(Iterator): """A cycle helper for templates.""" def __init__(self, *items): |