PY3 -> PY2 macro

This commit is contained in:
Armin Ronacher 2013-05-19 14:34:54 +01:00
parent 630804f67d
commit 7e245e2678
10 changed files with 95 additions and 58 deletions

View File

@ -3,54 +3,88 @@
jinja2._compat
~~~~~~~~~~~~~~
Some py2/py3 compatibility support that is not yet available in
"six" 1.3.0. Generally all uses of six should go through this module
so that we have one central place to remove stuff from when we
eventually drop 2.x.
Some py2/py3 compatibility support based on a stripped down
version of six so we don't have to depend on a specific version
of it.
:copyright: Copyright 2013 by the Jinja team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import six
import sys
PY3 = six.PY3
PY2 = sys.version_info[0] == 2
# https://bitbucket.org/gutworth/six/issue/25/add-unichr
try:
unichr = unichr # py2
except NameError:
unichr = chr # py3
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
if not PY2:
unichr = chr
range_type = range
text_type = str
string_types = (str,)
iteritems = six.iteritems
iterkeys = six.iterkeys
itervalues = six.itervalues
_iterkeys = 'keys'
_itervalues = 'values'
_iteritems = 'items'
if six.PY3:
from io import BytesIO, StringIO
NativeStringIO = StringIO
ifilter = filter
imap = map
izip = zip
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
Iterator = object
else:
text_type = unicode
unichr = unichr
string_types = (str, unicode)
_iterkeys = 'iterkeys'
_itervalues = 'itervalues'
_iteritems = 'iteritems'
from itertools import imap, izip, ifilter
range_type = xrange
from cStringIO import StringIO as BytesIO
from StringIO import StringIO
NativeStringIO = BytesIO
exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
class Iterator(object):
def next(self):
return self.__next__()
try:
next = next
except NameError:
def next(it):
return it.next()
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
return meta('NewBase', bases, {})
def iterkeys(d, **kw):
return iter(getattr(d, _iterkeys)(**kw))
def itervalues(d, **kw):
return iter(getattr(d, _itervalues)(**kw))
def iteritems(d, **kw):
return iter(getattr(d, _iteritems)(**kw))
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:

View File

@ -21,11 +21,11 @@ import tempfile
import fnmatch
from hashlib import sha1
from jinja2.utils import open_if_exists
from jinja2._compat import BytesIO, pickle, PY3
from jinja2._compat import BytesIO, pickle, PY2
# marshal works better on 3.x, one hack less required
if PY3:
if not PY2:
marshal_dump = marshal.dump
marshal_load = marshal.load
else:

View File

@ -28,7 +28,7 @@ from jinja2.exceptions import TemplateSyntaxError, TemplateNotFound, \
from jinja2.utils import import_string, LRUCache, Markup, missing, \
concat, consume, internalcode, _encode_filename
from jinja2._compat import imap, ifilter, string_types, iteritems, \
text_type, reraise, PY3, Iterator, next
text_type, reraise, PY2, Iterator, next
from functools import reduce
@ -1065,13 +1065,16 @@ class TemplateModule(object):
def __html__(self):
return Markup(concat(self._body_stream))
def __str__(self):
s = self.__unicode__()
return s if PY3 else s.encode('utf-8')
def __unicode__(self):
return concat(self._body_stream)
if PY2:
def __str__(self):
return self.__unicode__().encode('utf-8')
else:
__str__ = __unicode__
del __unicode__
def __repr__(self):
if self.__name__ is None:
name = 'memory:%x' % id(self)

View File

@ -8,13 +8,13 @@
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
from jinja2._compat import imap, text_type, PY3
from jinja2._compat import imap, text_type, PY2
class TemplateError(Exception):
"""Baseclass for all template errors."""
if not PY3:
if PY2:
def __init__(self, message=None):
if message is not None:
message = text_type(message).encode('utf-8')
@ -115,12 +115,12 @@ class TemplateSyntaxError(TemplateError):
return u'\n'.join(lines)
if PY3:
__str__ = __unicode__
del __unicode__
else:
if PY2:
def __str__(self):
return self.__unicode__().encode('utf-8')
else:
__str__ = __unicode__
del __unicode__
class TemplateAssertionError(TemplateSyntaxError):

View File

@ -15,7 +15,7 @@ from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \
from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
TemplateNotFound
from jinja2._compat import next, imap, text_type, iteritems, Iterator, \
string_types, PY3
string_types, PY2
# these variables are exported to the template runtime
@ -501,12 +501,12 @@ class Undefined(object):
def __unicode__(self):
return u''
if PY3:
__str__ = __unicode__
del __unicode__
else:
if PY2:
def __str__(self):
return self.__unicode__().encode('utf-8')
else:
__str__ = __unicode__
del __unicode__
def __len__(self):
return 0
@ -547,7 +547,7 @@ class DebugUndefined(Undefined):
)
return u'{{ undefined value printed: %s }}' % self._undefined_hint
if PY3:
if not PY2:
__str__ = __unicode__
del __unicode__
@ -575,7 +575,7 @@ class StrictUndefined(Undefined):
__iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \
__ne__ = __bool__ = Undefined._fail_with_undefined_error
if not PY3:
if PY2:
__unicode__ = Undefined._fail_with_undefined_error

View File

@ -16,7 +16,7 @@ import sys
import unittest
from traceback import format_exception
from jinja2 import loaders
from jinja2._compat import PY3
from jinja2._compat import PY2
here = os.path.dirname(os.path.abspath(__file__))
@ -90,7 +90,7 @@ def suite():
# doctests will not run on python 3 currently. Too many issues
# with that, do not test that on that platform.
if not PY3:
if PY2:
suite.addTest(doctests.suite())
return suite

View File

@ -12,7 +12,7 @@ import unittest
from jinja2.testsuite import JinjaTestCase
from jinja2 import Markup, Environment
from jinja2._compat import text_type, PY3
from jinja2._compat import text_type, PY2
env = Environment()
@ -299,12 +299,12 @@ class FilterTestCase(JinjaTestCase):
self.value = value
def __unicode__(self):
return text_type(self.value)
if PY3:
__str__ = __unicode__
del __unicode__
else:
if PY2:
def __str__(self):
return self.__unicode__().encode('utf-8')
else:
__str__ = __unicode__
del __unicode__
tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''')
assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234'

View File

@ -14,7 +14,7 @@ from jinja2.testsuite import JinjaTestCase
from jinja2 import Environment, Template, TemplateSyntaxError, \
UndefinedError, nodes
from jinja2._compat import next, iteritems, text_type, PY3
from jinja2._compat import next, iteritems, text_type, PY2
from jinja2.lexer import Token, TokenStream, TOKEN_EOF, \
TOKEN_BLOCK_BEGIN, TOKEN_BLOCK_END
@ -22,7 +22,7 @@ env = Environment()
# how does a string look like in jinja syntax?
if not PY3:
if PY2:
def jinja_string_repr(string):
return repr(string)[1:]
else:

View File

@ -23,7 +23,7 @@ except ImportError:
except ImportError:
from dummy_thread import allocate_lock
from collections import deque
from jinja2._compat import text_type, string_types, Iterator, PY3
from jinja2._compat import text_type, string_types, Iterator, PY2
_word_split_re = re.compile(r'(\s+)')
@ -53,7 +53,7 @@ concat = u''.join
# This is used in a couple of places. As far as Jinja is concerned
# filenames are unicode *or* bytestrings in 2.x and unicode only in
# 3.x because compile cannot handle bytes
if not PY3:
if PY2:
def _encode_filename(filename):
if isinstance(filename, unicode):
return filename.encode('utf-8')

View File

@ -80,7 +80,7 @@ setup(
'Topic :: Text Processing :: Markup :: HTML'
],
packages=['jinja2', 'jinja2.testsuite', 'jinja2.testsuite.res'],
install_requires=['six>=1.3.0', 'markupsafe'],
install_requires=['markupsafe'],
extras_require={'i18n': ['Babel>=0.8']},
test_suite='jinja2.testsuite.suite',
include_package_data=True,