1# cython: auto_cpdef=True 2 3'''Compatiblity for Python versions. 4 5Some of this code is "lifted" from CherryPy. 6''' 7from __future__ import absolute_import 8import sys 9from struct import unpack 10 11import json 12 13_encoding = 'UTF-8' 14 15if sys.version_info >= (3, 0): 16 from io import BytesIO as MemoryIO 17 from io import StringIO as StringIO 18 xrange = range 19 20 def py3_btou(n, encoding=_encoding): 21 return n.decode(encoding) 22 23 def py3_utob(n, encoding=_encoding): 24 return bytes(n, encoding) 25 26 def py3_json_dump(obj, **kwargs): 27 json.dump(obj, sys.stdout, **kwargs) 28 29 def py3_iterkeys(obj): 30 return obj.keys() 31 32 def py3_itervalues(obj): 33 return obj.values() 34 35 def py3_iteritems(obj): 36 return obj.items() 37 38 def py3_is_str(obj): 39 return isinstance(obj, str) 40 41 def py3_mk_bits(bits): 42 return bytes([bits & 0xff]) 43 44 def py3_bytes2ints(datum): 45 return list(datum) 46 47 def py3_fstint(datum): 48 return datum[0] 49 50 def py3_appendable(file_like): 51 if file_like.seekable() and file_like.tell() != 0: 52 if "<stdout>" == getattr(file_like, "name", ""): 53 # In OSX, sys.stdout is seekable and has a non-zero tell() but 54 # we wouldn't want to append to a stdout. In the python REPL, 55 # sys.stdout is named `<stdout>` 56 return False 57 if file_like.readable(): 58 return True 59 else: 60 raise ValueError( 61 "When appending to an avro file you must use the " 62 + "'a+' mode, not just 'a'" 63 ) 64 else: 65 return False 66 67 def py3_int_to_be_signed_bytes(num, bytes_req): 68 return num.to_bytes(bytes_req, byteorder='big', signed=True) 69 70 def py3_be_signed_bytes_to_int(data): 71 return int.from_bytes(data, byteorder='big', signed=True) 72 73 def py3_reraise(Err, msg): 74 raise Err(msg).with_traceback(sys.exc_info()[2]) 75 76else: # Python 2x 77 from cStringIO import StringIO as MemoryIO # noqa 78 from cStringIO import StringIO as StringIO # noqa 79 xrange = xrange 80 81 def py2_btou(n, encoding=_encoding): 82 return unicode(n, encoding) # noqa 83 84 def py2_utob(n, encoding=_encoding): 85 return n.encode(encoding) 86 87 _outenc = getattr(sys.stdout, 'encoding', None) or _encoding 88 89 def py2_json_dump(obj, **kwargs): 90 json.dump(obj, sys.stdout, encoding=_outenc, **kwargs) 91 92 def py2_iterkeys(obj): 93 return obj.iterkeys() 94 95 def py2_itervalues(obj): 96 return obj.itervalues() 97 98 def py2_iteritems(obj): 99 return obj.iteritems() 100 101 def py2_is_str(obj): 102 return isinstance(obj, basestring) # noqa 103 104 def py2_mk_bits(bits): 105 return chr(bits & 0xff) 106 107 def py2_str2ints(datum): 108 return map(lambda x: ord(x), datum) 109 110 def py2_fstint(datum): 111 return unpack('!b', datum[0])[0] 112 113 def _readable(file_like): 114 try: 115 file_like.read() 116 except Exception: 117 return False 118 return True 119 120 def py2_appendable(file_like): 121 # On Python 2 things are a mess. We basically just rely on looking at 122 # the mode. If that doesn't exist (like in the case of an io.BytesIO) 123 # then we check the position and readablility. 124 try: 125 file_like.mode 126 except AttributeError: 127 # This is probably some io stream so we rely on its tell() working 128 try: 129 if file_like.tell() != 0 and _readable(file_like): 130 return True 131 except (OSError, IOError): 132 pass 133 return False 134 135 if "a" in file_like.mode: 136 if "+" in file_like.mode: 137 return True 138 else: 139 raise ValueError( 140 "When appending to an avro file you must use the " 141 + "'a+' mode, not just 'a'" 142 ) 143 else: 144 return False 145 146 def py2_int_to_be_signed_bytes(num, bytes_req): 147 if num < 0: 148 num = 2 ** (8 * bytes_req) + num 149 hex_str = '%x' % num 150 hex_str = ((bytes_req * 2) - len(hex_str)) * '0' + hex_str 151 return hex_str.decode('hex') 152 153 def py2_be_signed_bytes_to_int(data): 154 output = int(data.encode('hex'), 16) 155 bitsize = len(data) * 8 156 if output < (2 ** (bitsize - 1)): 157 return output 158 return output - (2 ** bitsize) 159 160 def py2_reraise(Err, msg): 161 traceback = sys.exc_info()[2] 162 _locals = {'Err': Err, 'msg': msg, 'traceback': traceback} 163 exec('raise Err, msg, traceback', _locals) 164 165# We do it this way and not just redifine function since Cython do not like it 166if sys.version_info >= (3, 0): 167 btou = py3_btou 168 utob = py3_utob 169 json_dump = py3_json_dump 170 long = int 171 iterkeys = py3_iterkeys 172 itervalues = py3_itervalues 173 iteritems = py3_iteritems 174 is_str = py3_is_str 175 mk_bits = py3_mk_bits 176 str2ints = py3_bytes2ints 177 fstint = py3_fstint 178 appendable = py3_appendable 179 int_to_be_signed_bytes = py3_int_to_be_signed_bytes 180 be_signed_bytes_to_int = py3_be_signed_bytes_to_int 181 reraise = py3_reraise 182else: 183 btou = py2_btou 184 utob = py2_utob 185 json_dump = py2_json_dump 186 iterkeys = py2_iterkeys 187 itervalues = py2_itervalues 188 iteritems = py2_iteritems 189 long = long 190 is_str = py2_is_str 191 mk_bits = py2_mk_bits 192 str2ints = py2_str2ints 193 fstint = py2_fstint 194 appendable = py2_appendable 195 int_to_be_signed_bytes = py2_int_to_be_signed_bytes 196 be_signed_bytes_to_int = py2_be_signed_bytes_to_int 197 reraise = py2_reraise 198