From d6c9e63af9b574389dc4e27c44642d522f1abfbf Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 28 Jan 2003 03:49:52 +0000 Subject: First baby steps towards implementing protocol 2: PROTO, LONG1 and LONG4. --- Lib/pickle.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++- Lib/test/pickletester.py | 14 ++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/Lib/pickle.py b/Lib/pickle.py index cfad6ed..ebc2b68 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -176,6 +176,8 @@ class Pickler: object, or any other custom object that meets this interface. """ + if not 0 <= proto <= 2: + raise ValueError, "pickle protocol must be 0, 1 or 2" self.write = file.write self.memo = {} self.proto = proto @@ -199,6 +201,8 @@ class Pickler: value of the bin flag passed to the constructor. """ + if self.proto >= 2: + self.write(PROTO + chr(self.proto)) self.save(object) self.write(STOP) @@ -385,7 +389,14 @@ class Pickler: self.write(INT + `object` + '\n') dispatch[IntType] = save_int - def save_long(self, object): + def save_long(self, object, pack=struct.pack): + if self.proto >= 2: + bytes = encode_long(object) + n = len(bytes) + if n < 256: + self.write(LONG1 + chr(n) + bytes) + else: + self.write(LONG4 + pack(">> encode_long(255L) + '\xff\x00' + >>> encode_long(32767L) + '\xff\x7f' + >>> encode_long(-256L) + '\x00\xff' + >>> encode_long(-32768L) + '\x00\x80' + >>> encode_long(-128L) + '\x80' + >>> encode_long(127L) + '\x7f' + >>> + """ + digits = [] + while not -128 <= x < 128: + digits.append(x & 0xff) + x >>= 8 + digits.append(x & 0xff) + return "".join(map(chr, digits)) + +def decode_long(data): + r"""Decode a long from a two's complement little-endian binary string. + >>> decode_long("\xff\x00") + 255L + >>> decode_long("\xff\x7f") + 32767L + >>> decode_long("\x00\xff") + -256L + >>> decode_long("\x00\x80") + -32768L + >>> decode_long("\x80") + -128L + >>> decode_long("\x7f") + 127L + """ + x = 0L + i = 0L + for c in data: + x |= long(ord(c)) << i + i += 8L + if data and ord(c) >= 0x80: + x -= 1L << i + return x + # Shorthands try: @@ -1102,3 +1180,12 @@ def load(file): def loads(str): file = StringIO(str) return Unpickler(file).load() + +# Doctest + +def _test(): + import doctest + return doctest.testmod() + +if __name__ == "__main__": + _test() diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 7c031ec..85887ea 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -267,6 +267,20 @@ class AbstractPickleTests(unittest.TestCase): u = self.loads(s) self.assertEqual(t, u) + # Tests for protocol 2 + + def test_long1(self): + x = 12345678910111213141516178920L + s = self.dumps(x, 2) + y = self.loads(s) + self.assertEqual(x, y) + + def test_long4(self): + x = 12345678910111213141516178920L << (256*8) + s = self.dumps(x, 2) + y = self.loads(s) + self.assertEqual(x, y) + class AbstractPickleModuleTests(unittest.TestCase): def test_dump_closed_file(self): -- cgit v0.12