Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
rencode -- Web safe object pickling/unpickling.
Public domain, Connelly Barnes 2006-2007.
The rencode module is a modified version of bencode from the BitTorrent project. For complex, heterogeneous data structures with many small elements, r-encodings take up significantly less space than b-encodings:
>>> len(rencode.dumps({'a':0, 'b':[1,2], 'c':99})) 13 >>> len(bencode.bencode({'a':0, 'b':[1,2], 'c':99})) 26
The rencode format is not standardized, and may change with different rencode module versions, so you should check that you are using the same rencode version throughout your project. """
# Original bencode module by Petru Paler, et al. # # Modifications by Connelly Barnes: # # - Added support for floats (sent as 32-bit or 64-bit in network # order), bools, None. # - Allowed dict keys to be of any serializable type. # - Lists/tuples are always decoded as tuples (thus, tuples can be # used as dict keys). # - Embedded extra information in the 'typecodes' to save some space. # - Added a restriction on integer length, so that malicious hosts # cannot pass us large integers which take a long time to decode. # # Licensed by Bram Cohen under the "MIT license": # # "Copyright (C) 2001-2002 Bram Cohen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # The Software is provided "AS IS", without warranty of any kind, # express or implied, including but not limited to the warranties of # merchantability, fitness for a particular purpose and # noninfringement. In no event shall the authors or copyright holders # be liable for any claim, damages or other liability, whether in an # action of contract, tort or otherwise, arising from, out of or in # connection with the Software or the use or other dealings in the # Software." # # (The rencode module is licensed under the above license as well). #
# Default number of bits for serialized floats, either 32 or 64 (also a parameter for dumps()).
# Maximum length of integer when written as base 10 string.
# The bencode 'typecodes' such as i, d, etc have been extended and # relocated on the base-256 character set.
# Positive integers with value embedded in typecode.
# Dictionaries with length embedded in typecode.
# Negative integers with value embedded in typecode.
# Strings with length embedded in typecode.
# Lists with length embedded in typecode.
# Whether strings should be decoded when loading
f += 1 newf = x.index(CHR_TERM, f) if newf - f >= MAX_INT_LENGTH: raise ValueError('overflow') try: n = int(x[f:newf]) except (OverflowError, ValueError): n = long(x[f:newf]) if x[f] == '-': if x[f + 1] == '0': raise ValueError elif x[f] == '0' and newf != f + 1: raise ValueError return (n, newf + 1)
f += 1 return (struct.unpack('!b', x[f:f + 1])[0], f + 1)
f += 1 return (struct.unpack('!h', x[f:f + 2])[0], f + 2)
f += 1 return (struct.unpack('!q', x[f:f + 8])[0], f + 8)
f += 1 n = struct.unpack('!d', x[f:f + 8])[0] return (n, f + 8)
except (OverflowError, ValueError): n = long(x[f:colon]) raise ValueError
r, f = [], f + 1 while x[f] != CHR_TERM: v, f = decode_func[x[f]](x, f) r.append(v) return (tuple(r), f + 1)
r, f = {}, f + 1 while x[f] != CHR_TERM: k, f = decode_func[x[f]](x, f) r[k], f = decode_func[x[f]](x, f) return (r, f + 1)
return (False, f + 1)
return (None, f + 1)
global _decode_utf8 except (IndexError, KeyError): raise ValueError raise ValueError
r.append(chr(INT_NEG_FIXED_START - 1 - x)) r.extend((CHR_INT1, struct.pack('!b', x))) r.extend((CHR_INT2, struct.pack('!h', x))) elif -9223372036854775808 <= x < 9223372036854775808: r.extend((CHR_INT8, struct.pack('!q', x))) else: s = str(x) if len(s) >= MAX_INT_LENGTH: raise ValueError('overflow') r.extend((CHR_INT, s, CHR_TERM))
r.extend((CHR_FLOAT64, struct.pack('!d', x)))
r.extend(CHR_NONE)
else: r.extend((str(len(x)), ':', x))
else: r.append(CHR_LIST) for i in x: encode_func[type(i)](i, r) r.append(CHR_TERM)
else: r.append(CHR_DICT) for k, v in x.items(): encode_func[type(k)](k, r) encode_func[type(v)](v, r) r.append(CHR_TERM)
except ImportError: pass
""" Dump data structure to str.
Here float_bits is either 32 or 64. """ elif float_bits == 64: encode_func[FloatType] = encode_float64 else: raise ValueError('Float bits (%d) is not 32 or 64' % float_bits) finally:
f1 = struct.unpack('!f', struct.pack('!f', 25.5))[0] f2 = struct.unpack('!f', struct.pack('!f', 29.3))[0] f3 = struct.unpack('!f', struct.pack('!f', -0.6))[0] ld = (({'a': 15, 'bb': f1, 'ccc': f2, '': (f3, (), False, True, '')}, ('a', 10 ** 20), tuple(range(-100000, 100000)), 'b' * 31, 'b' * 62, 'b' * 64, 2 ** 30, 2 ** 33, 2 ** 62, 2 ** 64, 2 ** 30, 2 ** 33, 2 ** 62, 2 ** 64, False, False, True, -1, 2, 0),) assert loads(dumps(ld)) == ld d = dict(zip(range(-100000, 100000), range(-100000, 100000))) d.update({'a': 20, 20: 40, 40: 41, f1: f2, f2: f3, f3: False, False: True, True: False}) ld = (d, {}, {5: 6}, {7: 7, True: 8}, {9: 10, 22: 39, 49: 50, 44: ''}) assert loads(dumps(ld)) == ld ld = ('', 'a' * 10, 'a' * 100, 'a' * 1000, 'a' * 10000, 'a' * 100000, 'a' * 1000000, 'a' * 10000000) assert loads(dumps(ld)) == ld ld = tuple([dict(zip(range(n), range(n))) for n in range(100)]) + ('b',) assert loads(dumps(ld)) == ld ld = tuple([dict(zip(range(n), range(-n, 0))) for n in range(100)]) + ('b',) assert loads(dumps(ld)) == ld ld = tuple([tuple(range(n)) for n in range(100)]) + ('b',) assert loads(dumps(ld)) == ld ld = tuple(['a' * n for n in range(1000)]) + ('b',) assert loads(dumps(ld)) == ld ld = tuple(['a' * n for n in range(1000)]) + (None, True, None) assert loads(dumps(ld)) == ld assert loads(dumps(None)) is None assert loads(dumps({None: None})) == {None: None} assert 1e-10 < abs(loads(dumps(1.1)) - 1.1) < 1e-6 assert 1e-10 < abs(loads(dumps(1.1, 32)) - 1.1) < 1e-6 assert abs(loads(dumps(1.1, 64)) - 1.1) < 1e-12 assert loads(dumps(u"Hello World!!")) psyco.bind(dumps) psyco.bind(loads)
test() |