blob: 2454af13eddfb2c57c6401cd58bc04ce172e80fd [file] [log] [blame]
Jeremy Hylton66426532001-10-15 21:38:56 +00001import unittest
Tim Peters4190fb82003-02-02 16:09:05 +00002import pickle
Tim Peters8587b3c2003-02-13 15:44:41 +00003import cPickle
Amaury Forgeot d'Arc47ccf0c2009-07-23 22:31:47 +00004import StringIO
Tim Peters31f119e2003-02-03 16:20:13 +00005import pickletools
Georg Brandldffbf5f2008-05-20 07:49:57 +00006import copy_reg
Tim Peters4190fb82003-02-02 16:09:05 +00007
Georg Brandlde9b6242006-04-30 11:13:56 +00008from test.test_support import TestFailed, have_unicode, TESTFN, \
9 run_with_locale
Tim Peterse089c682001-04-10 03:41:41 +000010
Tim Petersee1a53c2003-02-02 02:57:53 +000011# Tests that try a number of pickle protocols should have a
12# for proto in protocols:
Tim Peters8587b3c2003-02-13 15:44:41 +000013# kind of outer loop.
14assert pickle.HIGHEST_PROTOCOL == cPickle.HIGHEST_PROTOCOL == 2
15protocols = range(pickle.HIGHEST_PROTOCOL + 1)
Tim Petersee1a53c2003-02-02 02:57:53 +000016
Tim Peters22e71712003-02-03 22:27:38 +000017
18# Return True if opcode code appears in the pickle, else False.
19def opcode_in_pickle(code, pickle):
20 for op, dummy, dummy in pickletools.genops(pickle):
21 if op.code == code:
22 return True
23 return False
24
Tim Peters8d2613a2003-02-11 16:40:16 +000025# Return the number of times opcode code appears in pickle.
26def count_opcode(code, pickle):
27 n = 0
28 for op, dummy, dummy in pickletools.genops(pickle):
29 if op.code == code:
30 n += 1
31 return n
32
Tim Peters3e667d52003-02-04 21:47:44 +000033# We can't very well test the extension registry without putting known stuff
34# in it, but we have to be careful to restore its original state. Code
35# should do this:
36#
37# e = ExtensionSaver(extension_code)
38# try:
39# fiddle w/ the extension registry's stuff for extension_code
40# finally:
41# e.restore()
42
43class ExtensionSaver:
44 # Remember current registration for code (if any), and remove it (if
45 # there is one).
46 def __init__(self, code):
47 self.code = code
Georg Brandldffbf5f2008-05-20 07:49:57 +000048 if code in copy_reg._inverted_registry:
49 self.pair = copy_reg._inverted_registry[code]
50 copy_reg.remove_extension(self.pair[0], self.pair[1], code)
Tim Peters3e667d52003-02-04 21:47:44 +000051 else:
52 self.pair = None
53
54 # Restore previous registration for code.
55 def restore(self):
56 code = self.code
Georg Brandldffbf5f2008-05-20 07:49:57 +000057 curpair = copy_reg._inverted_registry.get(code)
Tim Peters3e667d52003-02-04 21:47:44 +000058 if curpair is not None:
Georg Brandldffbf5f2008-05-20 07:49:57 +000059 copy_reg.remove_extension(curpair[0], curpair[1], code)
Tim Peters3e667d52003-02-04 21:47:44 +000060 pair = self.pair
61 if pair is not None:
Georg Brandldffbf5f2008-05-20 07:49:57 +000062 copy_reg.add_extension(pair[0], pair[1], code)
Tim Peters3e667d52003-02-04 21:47:44 +000063
Jeremy Hylton66426532001-10-15 21:38:56 +000064class C:
65 def __cmp__(self, other):
66 return cmp(self.__dict__, other.__dict__)
67
68import __main__
69__main__.C = C
70C.__module__ = "__main__"
71
72class myint(int):
73 def __init__(self, x):
74 self.str = str(x)
75
76class initarg(C):
Guido van Rossum1444f672001-12-19 16:38:29 +000077
Jeremy Hylton66426532001-10-15 21:38:56 +000078 def __init__(self, a, b):
79 self.a = a
80 self.b = b
81
82 def __getinitargs__(self):
83 return self.a, self.b
84
Guido van Rossum04a86612001-12-19 16:58:54 +000085class metaclass(type):
86 pass
87
88class use_metaclass(object):
89 __metaclass__ = metaclass
90
Tim Peters70b02d72003-02-02 17:26:40 +000091# DATA0 .. DATA2 are the pickles we expect under the various protocols, for
92# the object returned by create_data().
Tim Petersee1a53c2003-02-02 02:57:53 +000093
Jeremy Hylton66426532001-10-15 21:38:56 +000094# break into multiple strings to avoid confusing font-lock-mode
Tim Peters70b02d72003-02-02 17:26:40 +000095DATA0 = """(lp1
Tim Peterse9358162001-01-22 22:05:20 +000096I0
97aL1L
Tim Peters461922a2001-04-09 20:07:05 +000098aF2
Tim Peterse9358162001-01-22 22:05:20 +000099ac__builtin__
100complex
Tim Peters461922a2001-04-09 20:07:05 +0000101p2
102""" + \
103"""(F3
104F0
105tRp3
106aI1
107aI-1
108aI255
109aI-255
110aI-256
111aI65535
112aI-65535
113aI-65536
114aI2147483647
115aI-2147483647
116aI-2147483648
117a""" + \
118"""(S'abc'
Tim Peterse9358162001-01-22 22:05:20 +0000119p4
120g4
Tim Peters461922a2001-04-09 20:07:05 +0000121""" + \
Guido van Rossum42f92da2001-04-16 00:28:21 +0000122"""(i__main__
Tim Peterse9358162001-01-22 22:05:20 +0000123C
124p5
Tim Peters461922a2001-04-09 20:07:05 +0000125""" + \
Tim Peterse9358162001-01-22 22:05:20 +0000126"""(dp6
127S'foo'
128p7
129I1
130sS'bar'
131p8
132I2
133sbg5
134tp9
135ag9
136aI5
137a.
138"""
139
Tim Peters70b02d72003-02-02 17:26:40 +0000140# Disassembly of DATA0.
141DATA0_DIS = """\
142 0: ( MARK
143 1: l LIST (MARK at 0)
144 2: p PUT 1
145 5: I INT 0
146 8: a APPEND
147 9: L LONG 1L
148 13: a APPEND
149 14: F FLOAT 2.0
150 17: a APPEND
151 18: c GLOBAL '__builtin__ complex'
152 39: p PUT 2
153 42: ( MARK
154 43: F FLOAT 3.0
155 46: F FLOAT 0.0
156 49: t TUPLE (MARK at 42)
157 50: R REDUCE
158 51: p PUT 3
159 54: a APPEND
160 55: I INT 1
161 58: a APPEND
162 59: I INT -1
163 63: a APPEND
164 64: I INT 255
165 69: a APPEND
166 70: I INT -255
167 76: a APPEND
168 77: I INT -256
169 83: a APPEND
170 84: I INT 65535
171 91: a APPEND
172 92: I INT -65535
173 100: a APPEND
174 101: I INT -65536
175 109: a APPEND
176 110: I INT 2147483647
177 122: a APPEND
178 123: I INT -2147483647
179 136: a APPEND
180 137: I INT -2147483648
181 150: a APPEND
182 151: ( MARK
183 152: S STRING 'abc'
184 159: p PUT 4
185 162: g GET 4
186 165: ( MARK
187 166: i INST '__main__ C' (MARK at 165)
188 178: p PUT 5
189 181: ( MARK
190 182: d DICT (MARK at 181)
191 183: p PUT 6
192 186: S STRING 'foo'
193 193: p PUT 7
194 196: I INT 1
195 199: s SETITEM
196 200: S STRING 'bar'
197 207: p PUT 8
198 210: I INT 2
199 213: s SETITEM
200 214: b BUILD
201 215: g GET 5
202 218: t TUPLE (MARK at 151)
203 219: p PUT 9
204 222: a APPEND
205 223: g GET 9
206 226: a APPEND
207 227: I INT 5
208 230: a APPEND
209 231: . STOP
210highest protocol among opcodes = 0
211"""
212
213DATA1 = (']q\x01(K\x00L1L\nG@\x00\x00\x00\x00\x00\x00\x00'
214 'c__builtin__\ncomplex\nq\x02(G@\x08\x00\x00\x00\x00\x00'
215 '\x00G\x00\x00\x00\x00\x00\x00\x00\x00tRq\x03K\x01J\xff\xff'
216 '\xff\xffK\xffJ\x01\xff\xff\xffJ\x00\xff\xff\xffM\xff\xff'
217 'J\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff\xff\xff\x7fJ\x01\x00'
218 '\x00\x80J\x00\x00\x00\x80(U\x03abcq\x04h\x04(c__main__\n'
219 'C\nq\x05oq\x06}q\x07(U\x03fooq\x08K\x01U\x03barq\tK\x02ubh'
220 '\x06tq\nh\nK\x05e.'
221 )
222
223# Disassembly of DATA1.
224DATA1_DIS = """\
225 0: ] EMPTY_LIST
226 1: q BINPUT 1
227 3: ( MARK
228 4: K BININT1 0
229 6: L LONG 1L
230 10: G BINFLOAT 2.0
231 19: c GLOBAL '__builtin__ complex'
232 40: q BINPUT 2
233 42: ( MARK
234 43: G BINFLOAT 3.0
235 52: G BINFLOAT 0.0
236 61: t TUPLE (MARK at 42)
237 62: R REDUCE
238 63: q BINPUT 3
239 65: K BININT1 1
240 67: J BININT -1
241 72: K BININT1 255
242 74: J BININT -255
243 79: J BININT -256
244 84: M BININT2 65535
245 87: J BININT -65535
246 92: J BININT -65536
247 97: J BININT 2147483647
248 102: J BININT -2147483647
249 107: J BININT -2147483648
250 112: ( MARK
251 113: U SHORT_BINSTRING 'abc'
252 118: q BINPUT 4
253 120: h BINGET 4
254 122: ( MARK
255 123: c GLOBAL '__main__ C'
256 135: q BINPUT 5
257 137: o OBJ (MARK at 122)
258 138: q BINPUT 6
259 140: } EMPTY_DICT
260 141: q BINPUT 7
261 143: ( MARK
262 144: U SHORT_BINSTRING 'foo'
263 149: q BINPUT 8
264 151: K BININT1 1
265 153: U SHORT_BINSTRING 'bar'
266 158: q BINPUT 9
267 160: K BININT1 2
268 162: u SETITEMS (MARK at 143)
269 163: b BUILD
270 164: h BINGET 6
271 166: t TUPLE (MARK at 112)
272 167: q BINPUT 10
273 169: h BINGET 10
274 171: K BININT1 5
275 173: e APPENDS (MARK at 3)
276 174: . STOP
277highest protocol among opcodes = 1
278"""
Tim Peterse0c446b2001-10-18 21:57:37 +0000279
Tim Petersfc273752003-03-02 04:54:24 +0000280DATA2 = ('\x80\x02]q\x01(K\x00\x8a\x01\x01G@\x00\x00\x00\x00\x00\x00\x00'
281 'c__builtin__\ncomplex\nq\x02G@\x08\x00\x00\x00\x00\x00\x00G\x00'
282 '\x00\x00\x00\x00\x00\x00\x00\x86Rq\x03K\x01J\xff\xff\xff\xffK'
283 '\xffJ\x01\xff\xff\xffJ\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xff'
284 'J\x00\x00\xff\xffJ\xff\xff\xff\x7fJ\x01\x00\x00\x80J\x00\x00\x00'
285 '\x80(U\x03abcq\x04h\x04(c__main__\nC\nq\x05oq\x06}q\x07(U\x03foo'
286 'q\x08K\x01U\x03barq\tK\x02ubh\x06tq\nh\nK\x05e.')
287
288# Disassembly of DATA2.
289DATA2_DIS = """\
290 0: \x80 PROTO 2
291 2: ] EMPTY_LIST
292 3: q BINPUT 1
293 5: ( MARK
294 6: K BININT1 0
295 8: \x8a LONG1 1L
296 11: G BINFLOAT 2.0
297 20: c GLOBAL '__builtin__ complex'
298 41: q BINPUT 2
299 43: G BINFLOAT 3.0
300 52: G BINFLOAT 0.0
301 61: \x86 TUPLE2
302 62: R REDUCE
303 63: q BINPUT 3
304 65: K BININT1 1
305 67: J BININT -1
306 72: K BININT1 255
307 74: J BININT -255
308 79: J BININT -256
309 84: M BININT2 65535
310 87: J BININT -65535
311 92: J BININT -65536
312 97: J BININT 2147483647
313 102: J BININT -2147483647
314 107: J BININT -2147483648
315 112: ( MARK
316 113: U SHORT_BINSTRING 'abc'
317 118: q BINPUT 4
318 120: h BINGET 4
319 122: ( MARK
320 123: c GLOBAL '__main__ C'
321 135: q BINPUT 5
322 137: o OBJ (MARK at 122)
323 138: q BINPUT 6
324 140: } EMPTY_DICT
325 141: q BINPUT 7
326 143: ( MARK
327 144: U SHORT_BINSTRING 'foo'
328 149: q BINPUT 8
329 151: K BININT1 1
330 153: U SHORT_BINSTRING 'bar'
331 158: q BINPUT 9
332 160: K BININT1 2
333 162: u SETITEMS (MARK at 143)
334 163: b BUILD
335 164: h BINGET 6
336 166: t TUPLE (MARK at 112)
337 167: q BINPUT 10
338 169: h BINGET 10
339 171: K BININT1 5
340 173: e APPENDS (MARK at 5)
341 174: . STOP
342highest protocol among opcodes = 2
343"""
344
Jeremy Hylton66426532001-10-15 21:38:56 +0000345def create_data():
Tim Peterse9358162001-01-22 22:05:20 +0000346 c = C()
347 c.foo = 1
348 c.bar = 2
349 x = [0, 1L, 2.0, 3.0+0j]
Tim Peters461922a2001-04-09 20:07:05 +0000350 # Append some integer test cases at cPickle.c's internal size
351 # cutoffs.
352 uint1max = 0xff
353 uint2max = 0xffff
354 int4max = 0x7fffffff
355 x.extend([1, -1,
356 uint1max, -uint1max, -uint1max-1,
357 uint2max, -uint2max, -uint2max-1,
358 int4max, -int4max, -int4max-1])
Tim Peterse9358162001-01-22 22:05:20 +0000359 y = ('abc', 'abc', c, c)
360 x.append(y)
361 x.append(y)
362 x.append(5)
Jeremy Hylton66426532001-10-15 21:38:56 +0000363 return x
Tim Petersc58440f2001-04-09 17:16:31 +0000364
Jeremy Hylton66426532001-10-15 21:38:56 +0000365class AbstractPickleTests(unittest.TestCase):
Tim Peters70b02d72003-02-02 17:26:40 +0000366 # Subclass must define self.dumps, self.loads, self.error.
Tim Petersc58440f2001-04-09 17:16:31 +0000367
Jeremy Hylton66426532001-10-15 21:38:56 +0000368 _testdata = create_data()
Tim Petersc58440f2001-04-09 17:16:31 +0000369
Jeremy Hylton66426532001-10-15 21:38:56 +0000370 def setUp(self):
Tim Peterse9358162001-01-22 22:05:20 +0000371 pass
Tim Petersc58440f2001-04-09 17:16:31 +0000372
Jeremy Hylton66426532001-10-15 21:38:56 +0000373 def test_misc(self):
374 # test various datatypes not tested by testdata
Tim Peters70b02d72003-02-02 17:26:40 +0000375 for proto in protocols:
376 x = myint(4)
377 s = self.dumps(x, proto)
378 y = self.loads(s)
379 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000380
Tim Peters70b02d72003-02-02 17:26:40 +0000381 x = (1, ())
382 s = self.dumps(x, proto)
383 y = self.loads(s)
384 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000385
Tim Peters70b02d72003-02-02 17:26:40 +0000386 x = initarg(1, x)
387 s = self.dumps(x, proto)
388 y = self.loads(s)
389 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000390
Jeremy Hylton66426532001-10-15 21:38:56 +0000391 # XXX test __reduce__ protocol?
392
Tim Peters70b02d72003-02-02 17:26:40 +0000393 def test_roundtrip_equality(self):
394 expected = self._testdata
395 for proto in protocols:
396 s = self.dumps(expected, proto)
397 got = self.loads(s)
398 self.assertEqual(expected, got)
Jeremy Hylton66426532001-10-15 21:38:56 +0000399
Tim Peters70b02d72003-02-02 17:26:40 +0000400 def test_load_from_canned_string(self):
401 expected = self._testdata
Tim Petersfc273752003-03-02 04:54:24 +0000402 for canned in DATA0, DATA1, DATA2:
Tim Peters70b02d72003-02-02 17:26:40 +0000403 got = self.loads(canned)
404 self.assertEqual(expected, got)
Jeremy Hylton66426532001-10-15 21:38:56 +0000405
Tim Peters70b02d72003-02-02 17:26:40 +0000406 # There are gratuitous differences between pickles produced by
407 # pickle and cPickle, largely because cPickle starts PUT indices at
408 # 1 and pickle starts them at 0. See XXX comment in cPickle's put2() --
409 # there's a comment with an exclamation point there whose meaning
410 # is a mystery. cPickle also suppresses PUT for objects with a refcount
411 # of 1.
412 def dont_test_disassembly(self):
413 from cStringIO import StringIO
414 from pickletools import dis
415
416 for proto, expected in (0, DATA0_DIS), (1, DATA1_DIS):
417 s = self.dumps(self._testdata, proto)
418 filelike = StringIO()
419 dis(s, out=filelike)
420 got = filelike.getvalue()
421 self.assertEqual(expected, got)
Jeremy Hylton66426532001-10-15 21:38:56 +0000422
423 def test_recursive_list(self):
424 l = []
425 l.append(l)
Tim Peters70b02d72003-02-02 17:26:40 +0000426 for proto in protocols:
427 s = self.dumps(l, proto)
428 x = self.loads(s)
Armin Rigo2b3eb402003-10-28 12:05:48 +0000429 self.assertEqual(len(x), 1)
430 self.assert_(x is x[0])
Jeremy Hylton66426532001-10-15 21:38:56 +0000431
Collin Wintere9a65142009-05-26 05:37:22 +0000432 def test_recursive_tuple(self):
433 t = ([],)
434 t[0].append(t)
435 for proto in protocols:
436 s = self.dumps(t, proto)
437 x = self.loads(s)
438 self.assertEqual(len(x), 1)
439 self.assertEqual(len(x[0]), 1)
440 self.assert_(x is x[0][0])
441
Jeremy Hylton66426532001-10-15 21:38:56 +0000442 def test_recursive_dict(self):
443 d = {}
444 d[1] = d
Tim Peters70b02d72003-02-02 17:26:40 +0000445 for proto in protocols:
446 s = self.dumps(d, proto)
447 x = self.loads(s)
Armin Rigo2b3eb402003-10-28 12:05:48 +0000448 self.assertEqual(x.keys(), [1])
449 self.assert_(x[1] is x)
Jeremy Hylton66426532001-10-15 21:38:56 +0000450
451 def test_recursive_inst(self):
452 i = C()
453 i.attr = i
Tim Peters70b02d72003-02-02 17:26:40 +0000454 for proto in protocols:
455 s = self.dumps(i, 2)
456 x = self.loads(s)
Armin Rigo2b3eb402003-10-28 12:05:48 +0000457 self.assertEqual(dir(x), dir(i))
458 self.assert_(x.attr is x)
Jeremy Hylton66426532001-10-15 21:38:56 +0000459
460 def test_recursive_multi(self):
461 l = []
462 d = {1:l}
463 i = C()
464 i.attr = d
465 l.append(i)
Tim Peters70b02d72003-02-02 17:26:40 +0000466 for proto in protocols:
467 s = self.dumps(l, proto)
468 x = self.loads(s)
Armin Rigo2b3eb402003-10-28 12:05:48 +0000469 self.assertEqual(len(x), 1)
470 self.assertEqual(dir(x[0]), dir(i))
471 self.assertEqual(x[0].attr.keys(), [1])
472 self.assert_(x[0].attr[1] is x)
Jeremy Hylton66426532001-10-15 21:38:56 +0000473
474 def test_garyp(self):
475 self.assertRaises(self.error, self.loads, 'garyp')
476
477 def test_insecure_strings(self):
478 insecure = ["abc", "2 + 2", # not quoted
Martin v. Löwis8a8da792002-08-14 07:46:28 +0000479 #"'abc' + 'def'", # not a single quoted string
Jeremy Hylton66426532001-10-15 21:38:56 +0000480 "'abc", # quote is not closed
481 "'abc\"", # open quote and close quote don't match
482 "'abc' ?", # junk after close quote
Martin v. Löwiseb3f00a2002-08-14 08:22:50 +0000483 "'\\'", # trailing backslash
Jeremy Hylton66426532001-10-15 21:38:56 +0000484 # some tests of the quoting rules
Martin v. Löwis8a8da792002-08-14 07:46:28 +0000485 #"'abc\"\''",
486 #"'\\\\a\'\'\'\\\'\\\\\''",
Jeremy Hylton66426532001-10-15 21:38:56 +0000487 ]
488 for s in insecure:
489 buf = "S" + s + "\012p0\012."
490 self.assertRaises(ValueError, self.loads, buf)
491
Martin v. Löwis339d0f72001-08-17 18:39:25 +0000492 if have_unicode:
Jeremy Hylton66426532001-10-15 21:38:56 +0000493 def test_unicode(self):
Benjamin Peterson828a7062008-12-27 17:05:29 +0000494 endcases = [u'', u'<\\u>', u'<\\\u1234>', u'<\n>',
495 u'<\\>', u'<\\\U00012345>']
Tim Petersee1a53c2003-02-02 02:57:53 +0000496 for proto in protocols:
497 for u in endcases:
498 p = self.dumps(u, proto)
499 u2 = self.loads(p)
500 self.assertEqual(u2, u)
Tim Peterse089c682001-04-10 03:41:41 +0000501
Alexandre Vassalotti966322f2008-12-27 07:16:40 +0000502 def test_unicode_high_plane(self):
503 t = u'\U00012345'
504 for proto in protocols:
505 p = self.dumps(t, proto)
506 t2 = self.loads(p)
507 self.assertEqual(t2, t)
508
Jeremy Hylton66426532001-10-15 21:38:56 +0000509 def test_ints(self):
510 import sys
Tim Petersee1a53c2003-02-02 02:57:53 +0000511 for proto in protocols:
512 n = sys.maxint
513 while n:
514 for expected in (-n, n):
515 s = self.dumps(expected, proto)
516 n2 = self.loads(s)
517 self.assertEqual(expected, n2)
518 n = n >> 1
Tim Peters19ef62d2001-08-28 22:21:18 +0000519
Jeremy Hylton66426532001-10-15 21:38:56 +0000520 def test_maxint64(self):
521 maxint64 = (1L << 63) - 1
522 data = 'I' + str(maxint64) + '\n.'
523 got = self.loads(data)
524 self.assertEqual(got, maxint64)
525
526 # Try too with a bogus literal.
527 data = 'I' + str(maxint64) + 'JUNK\n.'
528 self.assertRaises(ValueError, self.loads, data)
529
Tim Petersee1a53c2003-02-02 02:57:53 +0000530 def test_long(self):
531 for proto in protocols:
Tim Petersbf2674b2003-02-02 07:51:32 +0000532 # 256 bytes is where LONG4 begins.
Tim Petersee1a53c2003-02-02 02:57:53 +0000533 for nbits in 1, 8, 8*254, 8*255, 8*256, 8*257:
534 nbase = 1L << nbits
535 for npos in nbase-1, nbase, nbase+1:
536 for n in npos, -npos:
537 pickle = self.dumps(n, proto)
538 got = self.loads(pickle)
539 self.assertEqual(n, got)
540 # Try a monster. This is quadratic-time in protos 0 & 1, so don't
541 # bother with those.
Tim Petersee1a53c2003-02-02 02:57:53 +0000542 nbase = long("deadbeeffeedface", 16)
543 nbase += nbase << 1000000
544 for n in nbase, -nbase:
Tim Petersee1a53c2003-02-02 02:57:53 +0000545 p = self.dumps(n, 2)
Tim Petersee1a53c2003-02-02 02:57:53 +0000546 got = self.loads(p)
Tim Petersee1a53c2003-02-02 02:57:53 +0000547 self.assertEqual(n, got)
548
Mark Dickinson3df16922009-01-24 21:30:14 +0000549 def test_float(self):
550 test_values = [0.0, 4.94e-324, 1e-310, 7e-308, 6.626e-34, 0.1, 0.5,
551 3.14, 263.44582062374053, 6.022e23, 1e30]
552 test_values = test_values + [-x for x in test_values]
553 for proto in protocols:
554 for value in test_values:
555 pickle = self.dumps(value, proto)
556 got = self.loads(pickle)
557 self.assertEqual(value, got)
558
Georg Brandlde9b6242006-04-30 11:13:56 +0000559 @run_with_locale('LC_ALL', 'de_DE', 'fr_FR')
560 def test_float_format(self):
561 # make sure that floats are formatted locale independent
562 self.assertEqual(self.dumps(1.2)[0:3], 'F1.')
563
Jeremy Hylton66426532001-10-15 21:38:56 +0000564 def test_reduce(self):
Tim Peters19ef62d2001-08-28 22:21:18 +0000565 pass
Jeremy Hylton66426532001-10-15 21:38:56 +0000566
567 def test_getinitargs(self):
568 pass
569
Guido van Rossum04a86612001-12-19 16:58:54 +0000570 def test_metaclass(self):
571 a = use_metaclass()
Tim Peters70b02d72003-02-02 17:26:40 +0000572 for proto in protocols:
573 s = self.dumps(a, proto)
574 b = self.loads(s)
575 self.assertEqual(a.__class__, b.__class__)
Guido van Rossum04a86612001-12-19 16:58:54 +0000576
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000577 def test_structseq(self):
578 import time
Michael W. Hudson0e025302002-03-06 17:11:18 +0000579 import os
Tim Peters70b02d72003-02-02 17:26:40 +0000580
581 t = time.localtime()
582 for proto in protocols:
583 s = self.dumps(t, proto)
Michael W. Hudson0e025302002-03-06 17:11:18 +0000584 u = self.loads(s)
585 self.assertEqual(t, u)
Tim Peters70b02d72003-02-02 17:26:40 +0000586 if hasattr(os, "stat"):
587 t = os.stat(os.curdir)
588 s = self.dumps(t, proto)
589 u = self.loads(s)
590 self.assertEqual(t, u)
591 if hasattr(os, "statvfs"):
592 t = os.statvfs(os.curdir)
593 s = self.dumps(t, proto)
594 u = self.loads(s)
595 self.assertEqual(t, u)
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000596
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000597 # Tests for protocol 2
598
Tim Peters4190fb82003-02-02 16:09:05 +0000599 def test_proto(self):
600 build_none = pickle.NONE + pickle.STOP
601 for proto in protocols:
602 expected = build_none
603 if proto >= 2:
604 expected = pickle.PROTO + chr(proto) + expected
605 p = self.dumps(None, proto)
606 self.assertEqual(p, expected)
607
608 oob = protocols[-1] + 1 # a future protocol
609 badpickle = pickle.PROTO + chr(oob) + build_none
610 try:
611 self.loads(badpickle)
612 except ValueError, detail:
613 self.failUnless(str(detail).startswith(
614 "unsupported pickle protocol"))
615 else:
616 self.fail("expected bad protocol number to raise ValueError")
617
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000618 def test_long1(self):
619 x = 12345678910111213141516178920L
Tim Peters61bf2572003-02-03 21:31:22 +0000620 for proto in protocols:
621 s = self.dumps(x, proto)
622 y = self.loads(s)
623 self.assertEqual(x, y)
Tim Peters22e71712003-02-03 22:27:38 +0000624 self.assertEqual(opcode_in_pickle(pickle.LONG1, s), proto >= 2)
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000625
626 def test_long4(self):
627 x = 12345678910111213141516178920L << (256*8)
Tim Peters61bf2572003-02-03 21:31:22 +0000628 for proto in protocols:
629 s = self.dumps(x, proto)
630 y = self.loads(s)
631 self.assertEqual(x, y)
Tim Peters22e71712003-02-03 22:27:38 +0000632 self.assertEqual(opcode_in_pickle(pickle.LONG4, s), proto >= 2)
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000633
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000634 def test_short_tuples(self):
Tim Peters1d63c9f2003-02-02 20:29:39 +0000635 # Map (proto, len(tuple)) to expected opcode.
636 expected_opcode = {(0, 0): pickle.TUPLE,
637 (0, 1): pickle.TUPLE,
638 (0, 2): pickle.TUPLE,
639 (0, 3): pickle.TUPLE,
640 (0, 4): pickle.TUPLE,
641
642 (1, 0): pickle.EMPTY_TUPLE,
643 (1, 1): pickle.TUPLE,
644 (1, 2): pickle.TUPLE,
645 (1, 3): pickle.TUPLE,
646 (1, 4): pickle.TUPLE,
647
648 (2, 0): pickle.EMPTY_TUPLE,
649 (2, 1): pickle.TUPLE1,
650 (2, 2): pickle.TUPLE2,
651 (2, 3): pickle.TUPLE3,
652 (2, 4): pickle.TUPLE,
653 }
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000654 a = ()
Guido van Rossum025bc2f2003-01-28 04:20:02 +0000655 b = (1,)
656 c = (1, 2)
657 d = (1, 2, 3)
658 e = (1, 2, 3, 4)
Tim Peters4190fb82003-02-02 16:09:05 +0000659 for proto in protocols:
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000660 for x in a, b, c, d, e:
661 s = self.dumps(x, proto)
662 y = self.loads(s)
663 self.assertEqual(x, y, (proto, x, s, y))
Tim Peters1d63c9f2003-02-02 20:29:39 +0000664 expected = expected_opcode[proto, len(x)]
Tim Peters22e71712003-02-03 22:27:38 +0000665 self.assertEqual(opcode_in_pickle(expected, s), True)
Tim Peters1d63c9f2003-02-02 20:29:39 +0000666
Guido van Rossum7d97d312003-01-28 04:25:27 +0000667 def test_singletons(self):
Tim Peters61bf2572003-02-03 21:31:22 +0000668 # Map (proto, singleton) to expected opcode.
669 expected_opcode = {(0, None): pickle.NONE,
670 (1, None): pickle.NONE,
671 (2, None): pickle.NONE,
672
673 (0, True): pickle.INT,
674 (1, True): pickle.INT,
675 (2, True): pickle.NEWTRUE,
676
677 (0, False): pickle.INT,
678 (1, False): pickle.INT,
679 (2, False): pickle.NEWFALSE,
680 }
Tim Peters4190fb82003-02-02 16:09:05 +0000681 for proto in protocols:
Guido van Rossum7d97d312003-01-28 04:25:27 +0000682 for x in None, False, True:
683 s = self.dumps(x, proto)
684 y = self.loads(s)
685 self.assert_(x is y, (proto, x, s, y))
Tim Peters61bf2572003-02-03 21:31:22 +0000686 expected = expected_opcode[proto, x]
Tim Peters22e71712003-02-03 22:27:38 +0000687 self.assertEqual(opcode_in_pickle(expected, s), True)
Tim Peters3c67d792003-02-02 17:59:11 +0000688
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000689 def test_newobj_tuple(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000690 x = MyTuple([1, 2, 3])
691 x.foo = 42
692 x.bar = "hello"
Tim Peters894453a2003-02-03 22:32:18 +0000693 for proto in protocols:
694 s = self.dumps(x, proto)
695 y = self.loads(s)
696 self.assertEqual(tuple(x), tuple(y))
697 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000698
699 def test_newobj_list(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000700 x = MyList([1, 2, 3])
701 x.foo = 42
702 x.bar = "hello"
Tim Peters894453a2003-02-03 22:32:18 +0000703 for proto in protocols:
704 s = self.dumps(x, proto)
705 y = self.loads(s)
706 self.assertEqual(list(x), list(y))
707 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000708
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000709 def test_newobj_generic(self):
Tim Peters5013bd92003-02-03 22:28:41 +0000710 for proto in protocols:
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000711 for C in myclasses:
712 B = C.__base__
713 x = C(C.sample)
714 x.foo = 42
715 s = self.dumps(x, proto)
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000716 y = self.loads(s)
717 detail = (proto, C, B, x, y, type(y))
718 self.assertEqual(B(x), B(y), detail)
719 self.assertEqual(x.__dict__, y.__dict__, detail)
720
Georg Brandldffbf5f2008-05-20 07:49:57 +0000721 # Register a type with copy_reg, with extension code extcode. Pickle
Tim Peters22e71712003-02-03 22:27:38 +0000722 # an object of that type. Check that the resulting pickle uses opcode
723 # (EXT[124]) under proto 2, and not in proto 1.
Tim Peters3e667d52003-02-04 21:47:44 +0000724
Tim Peters22e71712003-02-03 22:27:38 +0000725 def produce_global_ext(self, extcode, opcode):
Tim Peters3e667d52003-02-04 21:47:44 +0000726 e = ExtensionSaver(extcode)
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000727 try:
Georg Brandldffbf5f2008-05-20 07:49:57 +0000728 copy_reg.add_extension(__name__, "MyList", extcode)
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000729 x = MyList([1, 2, 3])
730 x.foo = 42
731 x.bar = "hello"
732
Tim Peters22e71712003-02-03 22:27:38 +0000733 # Dump using protocol 1 for comparison.
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000734 s1 = self.dumps(x, 1)
Tim Peters3e667d52003-02-04 21:47:44 +0000735 self.assert_(__name__ in s1)
736 self.assert_("MyList" in s1)
737 self.assertEqual(opcode_in_pickle(opcode, s1), False)
738
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000739 y = self.loads(s1)
740 self.assertEqual(list(x), list(y))
741 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000742
Tim Peters22e71712003-02-03 22:27:38 +0000743 # Dump using protocol 2 for test.
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000744 s2 = self.dumps(x, 2)
Tim Peters3e667d52003-02-04 21:47:44 +0000745 self.assert_(__name__ not in s2)
746 self.assert_("MyList" not in s2)
747 self.assertEqual(opcode_in_pickle(opcode, s2), True)
748
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000749 y = self.loads(s2)
750 self.assertEqual(list(x), list(y))
751 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000752
753 finally:
Tim Peters3e667d52003-02-04 21:47:44 +0000754 e.restore()
Tim Peters22e71712003-02-03 22:27:38 +0000755
756 def test_global_ext1(self):
Tim Peters3e667d52003-02-04 21:47:44 +0000757 self.produce_global_ext(0x00000001, pickle.EXT1) # smallest EXT1 code
758 self.produce_global_ext(0x000000ff, pickle.EXT1) # largest EXT1 code
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000759
760 def test_global_ext2(self):
Tim Peters3e667d52003-02-04 21:47:44 +0000761 self.produce_global_ext(0x00000100, pickle.EXT2) # smallest EXT2 code
762 self.produce_global_ext(0x0000ffff, pickle.EXT2) # largest EXT2 code
763 self.produce_global_ext(0x0000abcd, pickle.EXT2) # check endianness
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000764
765 def test_global_ext4(self):
Tim Peters3e667d52003-02-04 21:47:44 +0000766 self.produce_global_ext(0x00010000, pickle.EXT4) # smallest EXT4 code
767 self.produce_global_ext(0x7fffffff, pickle.EXT4) # largest EXT4 code
768 self.produce_global_ext(0x12abcdef, pickle.EXT4) # check endianness
769
Tim Peters8d2613a2003-02-11 16:40:16 +0000770 def test_list_chunking(self):
771 n = 10 # too small to chunk
772 x = range(n)
773 for proto in protocols:
774 s = self.dumps(x, proto)
775 y = self.loads(s)
776 self.assertEqual(x, y)
777 num_appends = count_opcode(pickle.APPENDS, s)
778 self.assertEqual(num_appends, proto > 0)
779
780 n = 2500 # expect at least two chunks when proto > 0
781 x = range(n)
782 for proto in protocols:
783 s = self.dumps(x, proto)
784 y = self.loads(s)
785 self.assertEqual(x, y)
786 num_appends = count_opcode(pickle.APPENDS, s)
787 if proto == 0:
788 self.assertEqual(num_appends, 0)
789 else:
790 self.failUnless(num_appends >= 2)
791
792 def test_dict_chunking(self):
793 n = 10 # too small to chunk
794 x = dict.fromkeys(range(n))
795 for proto in protocols:
796 s = self.dumps(x, proto)
797 y = self.loads(s)
798 self.assertEqual(x, y)
799 num_setitems = count_opcode(pickle.SETITEMS, s)
800 self.assertEqual(num_setitems, proto > 0)
801
802 n = 2500 # expect at least two chunks when proto > 0
803 x = dict.fromkeys(range(n))
804 for proto in protocols:
805 s = self.dumps(x, proto)
806 y = self.loads(s)
807 self.assertEqual(x, y)
808 num_setitems = count_opcode(pickle.SETITEMS, s)
809 if proto == 0:
810 self.assertEqual(num_setitems, 0)
811 else:
812 self.failUnless(num_setitems >= 2)
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000813
Tim Peterse9ef2032003-02-13 18:42:00 +0000814 def test_simple_newobj(self):
815 x = object.__new__(SimpleNewObj) # avoid __init__
816 x.abc = 666
817 for proto in protocols:
818 s = self.dumps(x, proto)
819 self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s), proto >= 2)
820 y = self.loads(s) # will raise TypeError if __init__ called
821 self.assertEqual(y.abc, 666)
822 self.assertEqual(x.__dict__, y.__dict__)
823
Tim Peters42f08ac2003-02-11 22:43:24 +0000824 def test_newobj_list_slots(self):
825 x = SlotList([1, 2, 3])
826 x.foo = 42
827 x.bar = "hello"
828 s = self.dumps(x, 2)
829 y = self.loads(s)
830 self.assertEqual(list(x), list(y))
831 self.assertEqual(x.__dict__, y.__dict__)
832 self.assertEqual(x.foo, y.foo)
833 self.assertEqual(x.bar, y.bar)
834
Guido van Rossum2a30b212003-02-18 22:41:24 +0000835 def test_reduce_overrides_default_reduce_ex(self):
836 for proto in 0, 1, 2:
837 x = REX_one()
838 self.assertEqual(x._reduce_called, 0)
839 s = self.dumps(x, proto)
840 self.assertEqual(x._reduce_called, 1)
841 y = self.loads(s)
842 self.assertEqual(y._reduce_called, 0)
843
844 def test_reduce_ex_called(self):
845 for proto in 0, 1, 2:
846 x = REX_two()
847 self.assertEqual(x._proto, None)
848 s = self.dumps(x, proto)
849 self.assertEqual(x._proto, proto)
850 y = self.loads(s)
851 self.assertEqual(y._proto, None)
852
853 def test_reduce_ex_overrides_reduce(self):
854 for proto in 0, 1, 2:
855 x = REX_three()
856 self.assertEqual(x._proto, None)
857 s = self.dumps(x, proto)
858 self.assertEqual(x._proto, proto)
859 y = self.loads(s)
860 self.assertEqual(y._proto, None)
861
Žiga Seilnacht20f43d32007-03-15 11:44:55 +0000862 def test_reduce_ex_calls_base(self):
863 for proto in 0, 1, 2:
864 x = REX_four()
865 self.assertEqual(x._proto, None)
866 s = self.dumps(x, proto)
867 self.assertEqual(x._proto, proto)
868 y = self.loads(s)
869 self.assertEqual(y._proto, proto)
870
871 def test_reduce_calls_base(self):
872 for proto in 0, 1, 2:
873 x = REX_five()
874 self.assertEqual(x._reduce_called, 0)
875 s = self.dumps(x, proto)
876 self.assertEqual(x._reduce_called, 1)
877 y = self.loads(s)
878 self.assertEqual(y._reduce_called, 1)
879
Amaury Forgeot d'Arcc353ea72008-10-30 21:29:12 +0000880 def test_reduce_bad_iterator(self):
881 # Issue4176: crash when 4th and 5th items of __reduce__()
882 # are not iterators
883 class C(object):
884 def __reduce__(self):
885 # 4th item is not an iterator
886 return list, (), None, [], None
887 class D(object):
888 def __reduce__(self):
889 # 5th item is not an iterator
890 return dict, (), None, None, []
891
892 # Protocol 0 is less strict and also accept iterables.
893 for proto in 0, 1, 2:
894 try:
895 self.dumps(C(), proto)
896 except (AttributeError, pickle.PickleError, cPickle.PickleError):
897 pass
898 try:
899 self.dumps(D(), proto)
900 except (AttributeError, pickle.PickleError, cPickle.PickleError):
901 pass
902
Guido van Rossum2a30b212003-02-18 22:41:24 +0000903# Test classes for reduce_ex
904
905class REX_one(object):
906 _reduce_called = 0
907 def __reduce__(self):
908 self._reduce_called = 1
909 return REX_one, ()
910 # No __reduce_ex__ here, but inheriting it from object
911
912class REX_two(object):
913 _proto = None
914 def __reduce_ex__(self, proto):
915 self._proto = proto
916 return REX_two, ()
917 # No __reduce__ here, but inheriting it from object
918
919class REX_three(object):
920 _proto = None
921 def __reduce_ex__(self, proto):
922 self._proto = proto
923 return REX_two, ()
924 def __reduce__(self):
925 raise TestFailed, "This __reduce__ shouldn't be called"
926
Žiga Seilnacht20f43d32007-03-15 11:44:55 +0000927class REX_four(object):
928 _proto = None
929 def __reduce_ex__(self, proto):
930 self._proto = proto
931 return object.__reduce_ex__(self, proto)
932 # Calling base class method should succeed
933
934class REX_five(object):
935 _reduce_called = 0
936 def __reduce__(self):
937 self._reduce_called = 1
938 return object.__reduce__(self)
939 # This one used to fail with infinite recursion
940
Guido van Rossum2a30b212003-02-18 22:41:24 +0000941# Test classes for newobj
Tim Peters080c88b2003-02-15 03:01:11 +0000942
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000943class MyInt(int):
944 sample = 1
945
946class MyLong(long):
947 sample = 1L
948
949class MyFloat(float):
950 sample = 1.0
951
952class MyComplex(complex):
953 sample = 1.0 + 0.0j
954
955class MyStr(str):
956 sample = "hello"
957
958class MyUnicode(unicode):
959 sample = u"hello \u1234"
960
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000961class MyTuple(tuple):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000962 sample = (1, 2, 3)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000963
964class MyList(list):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000965 sample = [1, 2, 3]
966
967class MyDict(dict):
968 sample = {"a": 1, "b": 2}
969
970myclasses = [MyInt, MyLong, MyFloat,
Guido van Rossum206b9a72003-03-02 13:53:18 +0000971 MyComplex,
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000972 MyStr, MyUnicode,
973 MyTuple, MyList, MyDict]
974
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000975
Guido van Rossumc8d6ef52003-01-28 22:02:31 +0000976class SlotList(MyList):
977 __slots__ = ["foo"]
978
Tim Peterse9ef2032003-02-13 18:42:00 +0000979class SimpleNewObj(object):
980 def __init__(self, a, b, c):
981 # raise an error, to make sure this isn't called
982 raise TypeError("SimpleNewObj.__init__() didn't expect to get called")
983
Jeremy Hylton66426532001-10-15 21:38:56 +0000984class AbstractPickleModuleTests(unittest.TestCase):
985
986 def test_dump_closed_file(self):
Guido van Rossum3b0a3292002-08-09 16:38:32 +0000987 import os
988 f = open(TESTFN, "w")
989 try:
990 f.close()
991 self.assertRaises(ValueError, self.module.dump, 123, f)
992 finally:
993 os.remove(TESTFN)
Jeremy Hylton66426532001-10-15 21:38:56 +0000994
995 def test_load_closed_file(self):
Guido van Rossum3b0a3292002-08-09 16:38:32 +0000996 import os
997 f = open(TESTFN, "w")
998 try:
999 f.close()
1000 self.assertRaises(ValueError, self.module.dump, 123, f)
1001 finally:
1002 os.remove(TESTFN)
Jeremy Hylton4c8be852002-11-13 22:10:47 +00001003
Tim Petersc0c93702003-02-13 19:30:57 +00001004 def test_highest_protocol(self):
1005 # Of course this needs to be changed when HIGHEST_PROTOCOL changes.
1006 self.assertEqual(self.module.HIGHEST_PROTOCOL, 2)
1007
Martin v. Löwis544f1192004-07-27 05:22:33 +00001008 def test_callapi(self):
1009 from cStringIO import StringIO
1010 f = StringIO()
1011 # With and without keyword arguments
1012 self.module.dump(123, f, -1)
1013 self.module.dump(123, file=f, protocol=-1)
1014 self.module.dumps(123, -1)
1015 self.module.dumps(123, protocol=-1)
1016 self.module.Pickler(f, -1)
1017 self.module.Pickler(f, protocol=-1)
Tim Petersc0c93702003-02-13 19:30:57 +00001018
Amaury Forgeot d'Arc47ccf0c2009-07-23 22:31:47 +00001019 def test_incomplete_input(self):
1020 s = StringIO.StringIO("X''.")
1021 self.assertRaises(EOFError, self.module.load, s)
1022
Alexandre Vassalotti513c46e2009-11-24 18:06:51 +00001023 def test_restricted(self):
1024 # issue7128: cPickle failed in restricted mode
1025 builtins = {self.module.__name__: self.module,
1026 '__import__': __import__}
1027 d = {}
1028 teststr = "def f(): {0}.dumps(0)".format(self.module.__name__)
1029 exec teststr in {'__builtins__': builtins}, d
1030 d['f']()
1031
Antoine Pitrou8dba7272010-01-07 18:04:12 +00001032 def test_bad_input(self):
1033 # Test issue4298
1034 s = '\x58\0\0\0\x54'
1035 self.assertRaises(EOFError, self.module.loads, s)
1036 # Test issue7455
1037 s = '0'
1038 # XXX Why doesn't pickle raise UnpicklingError?
1039 self.assertRaises((IndexError, cPickle.UnpicklingError),
1040 self.module.loads, s)
Alexandre Vassalotti513c46e2009-11-24 18:06:51 +00001041
Jeremy Hylton4c8be852002-11-13 22:10:47 +00001042class AbstractPersistentPicklerTests(unittest.TestCase):
1043
1044 # This class defines persistent_id() and persistent_load()
1045 # functions that should be used by the pickler. All even integers
1046 # are pickled using persistent ids.
1047
1048 def persistent_id(self, object):
1049 if isinstance(object, int) and object % 2 == 0:
1050 self.id_count += 1
1051 return str(object)
1052 else:
1053 return None
1054
1055 def persistent_load(self, oid):
1056 self.load_count += 1
1057 object = int(oid)
1058 assert object % 2 == 0
1059 return object
1060
1061 def test_persistence(self):
1062 self.id_count = 0
1063 self.load_count = 0
1064 L = range(10)
1065 self.assertEqual(self.loads(self.dumps(L)), L)
1066 self.assertEqual(self.id_count, 5)
1067 self.assertEqual(self.load_count, 5)
1068
1069 def test_bin_persistence(self):
1070 self.id_count = 0
1071 self.load_count = 0
1072 L = range(10)
1073 self.assertEqual(self.loads(self.dumps(L, 1)), L)
1074 self.assertEqual(self.id_count, 5)
1075 self.assertEqual(self.load_count, 5)