1 # -*- coding: utf-8 -*- 2 """ 3 jinja2._compat 4 ~~~~~~~~~~~~~~ 5 6 Some py2/py3 compatibility support based on a stripped down 7 version of six so we don't have to depend on a specific version 8 of it. 9 10 :copyright: Copyright 2013 by the Jinja team, see AUTHORS. 11 :license: BSD, see LICENSE for details. 12 """ 13 import sys 14 15 PY2 = sys.version_info[0] == 2 16 PYPY = hasattr(sys, 'pypy_translation_info') 17 _identity = lambda x: x 18 19 20 if not PY2: 21 unichr = chr 22 range_type = range 23 text_type = str 24 string_types = (str,) 25 26 iterkeys = lambda d: iter(d.keys()) 27 itervalues = lambda d: iter(d.values()) 28 iteritems = lambda d: iter(d.items()) 29 30 import pickle 31 from io import BytesIO, StringIO 32 NativeStringIO = StringIO 33 34 def reraise(tp, value, tb=None): 35 if value.__traceback__ is not tb: 36 raise value.with_traceback(tb) 37 raise value 38 39 ifilter = filter 40 imap = map 41 izip = zip 42 intern = sys.intern 43 44 implements_iterator = _identity 45 implements_to_string = _identity 46 encode_filename = _identity 47 get_next = lambda x: x.__next__ 48 49 else: 50 unichr = unichr 51 text_type = unicode 52 range_type = xrange 53 string_types = (str, unicode) 54 55 iterkeys = lambda d: d.iterkeys() 56 itervalues = lambda d: d.itervalues() 57 iteritems = lambda d: d.iteritems() 58 59 import cPickle as pickle 60 from cStringIO import StringIO as BytesIO, StringIO 61 NativeStringIO = BytesIO 62 63 exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') 64 65 from itertools import imap, izip, ifilter 66 intern = intern 67 68 def implements_iterator(cls): 69 cls.next = cls.__next__ 70 del cls.__next__ 71 return cls 72 73 def implements_to_string(cls): 74 cls.__unicode__ = cls.__str__ 75 cls.__str__ = lambda x: x.__unicode__().encode('utf-8') 76 return cls 77 78 get_next = lambda x: x.next 79 80 def encode_filename(filename): 81 if isinstance(filename, unicode): 82 return filename.encode('utf-8') 83 return filename 84 85 try: 86 next = next 87 except NameError: 88 def next(it): 89 return it.next() 90 91 92 def with_metaclass(meta, *bases): 93 # This requires a bit of explanation: the basic idea is to make a 94 # dummy metaclass for one level of class instanciation that replaces 95 # itself with the actual metaclass. Because of internal type checks 96 # we also need to make sure that we downgrade the custom metaclass 97 # for one level to something closer to type (that's why __call__ and 98 # __init__ comes back from type etc.). 99 # 100 # This has the advantage over six.with_metaclass in that it does not 101 # introduce dummy classes into the final MRO. 102 class metaclass(meta): 103 __call__ = type.__call__ 104 __init__ = type.__init__ 105 def __new__(cls, name, this_bases, d): 106 if this_bases is None: 107 return type.__new__(cls, name, (), d) 108 return meta(name, bases, d) 109 return metaclass('temporary_class', None, {}) 110 111 112 try: 113 from collections import Mapping as mapping_types 114 except ImportError: 115 import UserDict 116 mapping_types = (UserDict.UserDict, UserDict.DictMixin, dict) 117 118 119 # common types. These do exist in the special types module too which however 120 # does not exist in IronPython out of the box. Also that way we don't have 121 # to deal with implementation specific stuff here 122 class _C(object): 123 def method(self): pass 124 def _func(): 125 yield None 126 function_type = type(_func) 127 generator_type = type(_func()) 128 method_type = type(_C().method) 129 code_type = type(_C.method.__code__) 130 try: 131 raise TypeError() 132 except TypeError: 133 _tb = sys.exc_info()[2] 134 traceback_type = type(_tb) 135 frame_type = type(_tb.tb_frame) 136 137 138 try: 139 from urllib.parse import quote_from_bytes as url_quote 140 except ImportError: 141 from urllib import quote as url_quote 142 143 144 try: 145 from thread import allocate_lock 146 except ImportError: 147 try: 148 from threading import Lock as allocate_lock 149 except ImportError: 150 from dummy_thread import allocate_lock 151