blob: 5ef0cf2e2484b417853dfcba1f72b22616c57d89 [file] [log] [blame]
Jeremy Hylton66426532001-10-15 21:38:56 +00001import unittest
Tim Peters4190fb82003-02-02 16:09:05 +00002import pickle
3
Guido van Rossum3b0a3292002-08-09 16:38:32 +00004from test.test_support import TestFailed, have_unicode, TESTFN
Tim Peterse089c682001-04-10 03:41:41 +00005
Tim Petersee1a53c2003-02-02 02:57:53 +00006# Tests that try a number of pickle protocols should have a
7# for proto in protocols:
8# kind of outer loop. Bump the 3 to 4 if/when protocol 3 is invented.
9protocols = range(3)
10
Jeremy Hylton66426532001-10-15 21:38:56 +000011class C:
12 def __cmp__(self, other):
13 return cmp(self.__dict__, other.__dict__)
14
15import __main__
16__main__.C = C
17C.__module__ = "__main__"
18
19class myint(int):
20 def __init__(self, x):
21 self.str = str(x)
22
23class initarg(C):
Guido van Rossum1444f672001-12-19 16:38:29 +000024
Jeremy Hylton66426532001-10-15 21:38:56 +000025 def __init__(self, a, b):
26 self.a = a
27 self.b = b
28
29 def __getinitargs__(self):
30 return self.a, self.b
31
Guido van Rossum04a86612001-12-19 16:58:54 +000032class metaclass(type):
33 pass
34
35class use_metaclass(object):
36 __metaclass__ = metaclass
37
Tim Petersee1a53c2003-02-02 02:57:53 +000038# DATA and BINDATA are the protocol 0 and protocol 1 pickles of the object
39# returned by create_data().
40
Jeremy Hylton66426532001-10-15 21:38:56 +000041# break into multiple strings to avoid confusing font-lock-mode
Tim Peters461922a2001-04-09 20:07:05 +000042DATA = """(lp1
Tim Peterse9358162001-01-22 22:05:20 +000043I0
44aL1L
Tim Peters461922a2001-04-09 20:07:05 +000045aF2
Tim Peterse9358162001-01-22 22:05:20 +000046ac__builtin__
47complex
Tim Peters461922a2001-04-09 20:07:05 +000048p2
49""" + \
50"""(F3
51F0
52tRp3
53aI1
54aI-1
55aI255
56aI-255
57aI-256
58aI65535
59aI-65535
60aI-65536
61aI2147483647
62aI-2147483647
63aI-2147483648
64a""" + \
65"""(S'abc'
Tim Peterse9358162001-01-22 22:05:20 +000066p4
67g4
Tim Peters461922a2001-04-09 20:07:05 +000068""" + \
Guido van Rossum42f92da2001-04-16 00:28:21 +000069"""(i__main__
Tim Peterse9358162001-01-22 22:05:20 +000070C
71p5
Tim Peters461922a2001-04-09 20:07:05 +000072""" + \
Tim Peterse9358162001-01-22 22:05:20 +000073"""(dp6
74S'foo'
75p7
76I1
77sS'bar'
78p8
79I2
80sbg5
81tp9
82ag9
83aI5
84a.
85"""
86
Tim Peters461922a2001-04-09 20:07:05 +000087BINDATA = ']q\x01(K\x00L1L\nG@\x00\x00\x00\x00\x00\x00\x00' + \
88 'c__builtin__\ncomplex\nq\x02(G@\x08\x00\x00\x00\x00\x00' + \
89 '\x00G\x00\x00\x00\x00\x00\x00\x00\x00tRq\x03K\x01J\xff\xff' + \
90 '\xff\xffK\xffJ\x01\xff\xff\xffJ\x00\xff\xff\xffM\xff\xff' + \
91 'J\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff\xff\xff\x7fJ\x01\x00' + \
Guido van Rossum42f92da2001-04-16 00:28:21 +000092 '\x00\x80J\x00\x00\x00\x80(U\x03abcq\x04h\x04(c__main__\n' + \
Tim Peters461922a2001-04-09 20:07:05 +000093 'C\nq\x05oq\x06}q\x07(U\x03fooq\x08K\x01U\x03barq\tK\x02ubh' + \
94 '\x06tq\nh\nK\x05e.'
Tim Peterse0c446b2001-10-18 21:57:37 +000095
Jeremy Hylton66426532001-10-15 21:38:56 +000096def create_data():
Tim Peterse9358162001-01-22 22:05:20 +000097 c = C()
98 c.foo = 1
99 c.bar = 2
100 x = [0, 1L, 2.0, 3.0+0j]
Tim Peters461922a2001-04-09 20:07:05 +0000101 # Append some integer test cases at cPickle.c's internal size
102 # cutoffs.
103 uint1max = 0xff
104 uint2max = 0xffff
105 int4max = 0x7fffffff
106 x.extend([1, -1,
107 uint1max, -uint1max, -uint1max-1,
108 uint2max, -uint2max, -uint2max-1,
109 int4max, -int4max, -int4max-1])
Tim Peterse9358162001-01-22 22:05:20 +0000110 y = ('abc', 'abc', c, c)
111 x.append(y)
112 x.append(y)
113 x.append(5)
Jeremy Hylton66426532001-10-15 21:38:56 +0000114 return x
Tim Petersc58440f2001-04-09 17:16:31 +0000115
Jeremy Hylton66426532001-10-15 21:38:56 +0000116class AbstractPickleTests(unittest.TestCase):
Tim Petersc58440f2001-04-09 17:16:31 +0000117
Jeremy Hylton66426532001-10-15 21:38:56 +0000118 _testdata = create_data()
Tim Petersc58440f2001-04-09 17:16:31 +0000119
Jeremy Hylton66426532001-10-15 21:38:56 +0000120 def setUp(self):
121 # subclass must define self.dumps, self.loads, self.error
Tim Peterse9358162001-01-22 22:05:20 +0000122 pass
Tim Petersc58440f2001-04-09 17:16:31 +0000123
Jeremy Hylton66426532001-10-15 21:38:56 +0000124 def test_misc(self):
125 # test various datatypes not tested by testdata
126 x = myint(4)
127 s = self.dumps(x)
128 y = self.loads(s)
129 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000130
Jeremy Hylton66426532001-10-15 21:38:56 +0000131 x = (1, ())
132 s = self.dumps(x)
133 y = self.loads(s)
134 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000135
Jeremy Hylton66426532001-10-15 21:38:56 +0000136 x = initarg(1, x)
137 s = self.dumps(x)
138 y = self.loads(s)
139 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000140
Jeremy Hylton66426532001-10-15 21:38:56 +0000141 # XXX test __reduce__ protocol?
142
143 def test_identity(self):
144 s = self.dumps(self._testdata)
145 x = self.loads(s)
146 self.assertEqual(x, self._testdata)
147
148 def test_constant(self):
149 x = self.loads(DATA)
150 self.assertEqual(x, self._testdata)
151 x = self.loads(BINDATA)
152 self.assertEqual(x, self._testdata)
153
154 def test_binary(self):
155 s = self.dumps(self._testdata, 1)
156 x = self.loads(s)
157 self.assertEqual(x, self._testdata)
158
159 def test_recursive_list(self):
160 l = []
161 l.append(l)
162 s = self.dumps(l)
163 x = self.loads(s)
164 self.assertEqual(x, l)
165 self.assertEqual(x, x[0])
166 self.assertEqual(id(x), id(x[0]))
167
168 def test_recursive_dict(self):
169 d = {}
170 d[1] = d
171 s = self.dumps(d)
172 x = self.loads(s)
173 self.assertEqual(x, d)
174 self.assertEqual(x[1], x)
175 self.assertEqual(id(x[1]), id(x))
176
177 def test_recursive_inst(self):
178 i = C()
179 i.attr = i
180 s = self.dumps(i)
181 x = self.loads(s)
182 self.assertEqual(x, i)
183 self.assertEqual(x.attr, x)
184 self.assertEqual(id(x.attr), id(x))
185
186 def test_recursive_multi(self):
187 l = []
188 d = {1:l}
189 i = C()
190 i.attr = d
191 l.append(i)
192 s = self.dumps(l)
193 x = self.loads(s)
194 self.assertEqual(x, l)
195 self.assertEqual(x[0], i)
196 self.assertEqual(x[0].attr, d)
197 self.assertEqual(x[0].attr[1], x)
198 self.assertEqual(x[0].attr[1][0], i)
199 self.assertEqual(x[0].attr[1][0].attr, d)
200
201 def test_garyp(self):
202 self.assertRaises(self.error, self.loads, 'garyp')
203
204 def test_insecure_strings(self):
205 insecure = ["abc", "2 + 2", # not quoted
Martin v. Löwis8a8da792002-08-14 07:46:28 +0000206 #"'abc' + 'def'", # not a single quoted string
Jeremy Hylton66426532001-10-15 21:38:56 +0000207 "'abc", # quote is not closed
208 "'abc\"", # open quote and close quote don't match
209 "'abc' ?", # junk after close quote
Martin v. Löwiseb3f00a2002-08-14 08:22:50 +0000210 "'\\'", # trailing backslash
Jeremy Hylton66426532001-10-15 21:38:56 +0000211 # some tests of the quoting rules
Martin v. Löwis8a8da792002-08-14 07:46:28 +0000212 #"'abc\"\''",
213 #"'\\\\a\'\'\'\\\'\\\\\''",
Jeremy Hylton66426532001-10-15 21:38:56 +0000214 ]
215 for s in insecure:
216 buf = "S" + s + "\012p0\012."
217 self.assertRaises(ValueError, self.loads, buf)
218
Martin v. Löwis339d0f72001-08-17 18:39:25 +0000219 if have_unicode:
Jeremy Hylton66426532001-10-15 21:38:56 +0000220 def test_unicode(self):
221 endcases = [unicode(''), unicode('<\\u>'), unicode('<\\\u1234>'),
222 unicode('<\n>'), unicode('<\\>')]
Tim Petersee1a53c2003-02-02 02:57:53 +0000223 for proto in protocols:
224 for u in endcases:
225 p = self.dumps(u, proto)
226 u2 = self.loads(p)
227 self.assertEqual(u2, u)
Tim Peterse089c682001-04-10 03:41:41 +0000228
Jeremy Hylton66426532001-10-15 21:38:56 +0000229 def test_ints(self):
230 import sys
Tim Petersee1a53c2003-02-02 02:57:53 +0000231 for proto in protocols:
232 n = sys.maxint
233 while n:
234 for expected in (-n, n):
235 s = self.dumps(expected, proto)
236 n2 = self.loads(s)
237 self.assertEqual(expected, n2)
238 n = n >> 1
Tim Peters19ef62d2001-08-28 22:21:18 +0000239
Jeremy Hylton66426532001-10-15 21:38:56 +0000240 def test_maxint64(self):
241 maxint64 = (1L << 63) - 1
242 data = 'I' + str(maxint64) + '\n.'
243 got = self.loads(data)
244 self.assertEqual(got, maxint64)
245
246 # Try too with a bogus literal.
247 data = 'I' + str(maxint64) + 'JUNK\n.'
248 self.assertRaises(ValueError, self.loads, data)
249
Tim Petersee1a53c2003-02-02 02:57:53 +0000250 def test_long(self):
251 for proto in protocols:
Tim Petersbf2674b2003-02-02 07:51:32 +0000252 # 256 bytes is where LONG4 begins.
Tim Petersee1a53c2003-02-02 02:57:53 +0000253 for nbits in 1, 8, 8*254, 8*255, 8*256, 8*257:
254 nbase = 1L << nbits
255 for npos in nbase-1, nbase, nbase+1:
256 for n in npos, -npos:
257 pickle = self.dumps(n, proto)
258 got = self.loads(pickle)
259 self.assertEqual(n, got)
260 # Try a monster. This is quadratic-time in protos 0 & 1, so don't
261 # bother with those.
Tim Petersee1a53c2003-02-02 02:57:53 +0000262 nbase = long("deadbeeffeedface", 16)
263 nbase += nbase << 1000000
264 for n in nbase, -nbase:
Tim Petersee1a53c2003-02-02 02:57:53 +0000265 p = self.dumps(n, 2)
Tim Petersee1a53c2003-02-02 02:57:53 +0000266 got = self.loads(p)
Tim Petersee1a53c2003-02-02 02:57:53 +0000267 self.assertEqual(n, got)
268
Jeremy Hylton66426532001-10-15 21:38:56 +0000269 def test_reduce(self):
Tim Peters19ef62d2001-08-28 22:21:18 +0000270 pass
Jeremy Hylton66426532001-10-15 21:38:56 +0000271
272 def test_getinitargs(self):
273 pass
274
Guido van Rossum04a86612001-12-19 16:58:54 +0000275 def test_metaclass(self):
276 a = use_metaclass()
277 s = self.dumps(a)
278 b = self.loads(s)
279 self.assertEqual(a.__class__, b.__class__)
280
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000281 def test_structseq(self):
282 import time
283 t = time.localtime()
284 s = self.dumps(t)
285 u = self.loads(s)
Tim Peters863ac442002-04-16 01:38:40 +0000286 self.assertEqual(t, u)
Michael W. Hudson0e025302002-03-06 17:11:18 +0000287 import os
288 if hasattr(os, "stat"):
289 t = os.stat(os.curdir)
290 s = self.dumps(t)
291 u = self.loads(s)
292 self.assertEqual(t, u)
293 if hasattr(os, "statvfs"):
294 t = os.statvfs(os.curdir)
295 s = self.dumps(t)
296 u = self.loads(s)
297 self.assertEqual(t, u)
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000298
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000299 # Tests for protocol 2
300
Tim Peters4190fb82003-02-02 16:09:05 +0000301 def test_proto(self):
302 build_none = pickle.NONE + pickle.STOP
303 for proto in protocols:
304 expected = build_none
305 if proto >= 2:
306 expected = pickle.PROTO + chr(proto) + expected
307 p = self.dumps(None, proto)
308 self.assertEqual(p, expected)
309
310 oob = protocols[-1] + 1 # a future protocol
311 badpickle = pickle.PROTO + chr(oob) + build_none
312 try:
313 self.loads(badpickle)
314 except ValueError, detail:
315 self.failUnless(str(detail).startswith(
316 "unsupported pickle protocol"))
317 else:
318 self.fail("expected bad protocol number to raise ValueError")
319
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000320 def test_long1(self):
321 x = 12345678910111213141516178920L
322 s = self.dumps(x, 2)
323 y = self.loads(s)
324 self.assertEqual(x, y)
325
326 def test_long4(self):
327 x = 12345678910111213141516178920L << (256*8)
328 s = self.dumps(x, 2)
329 y = self.loads(s)
330 self.assertEqual(x, y)
331
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000332 def test_short_tuples(self):
333 a = ()
Guido van Rossum025bc2f2003-01-28 04:20:02 +0000334 b = (1,)
335 c = (1, 2)
336 d = (1, 2, 3)
337 e = (1, 2, 3, 4)
Tim Peters4190fb82003-02-02 16:09:05 +0000338 for proto in protocols:
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000339 for x in a, b, c, d, e:
340 s = self.dumps(x, proto)
341 y = self.loads(s)
342 self.assertEqual(x, y, (proto, x, s, y))
343
Guido van Rossum7d97d312003-01-28 04:25:27 +0000344 def test_singletons(self):
Tim Peters4190fb82003-02-02 16:09:05 +0000345 for proto in protocols:
Guido van Rossum7d97d312003-01-28 04:25:27 +0000346 for x in None, False, True:
347 s = self.dumps(x, proto)
348 y = self.loads(s)
349 self.assert_(x is y, (proto, x, s, y))
350
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000351 def test_newobj_tuple(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000352 x = MyTuple([1, 2, 3])
353 x.foo = 42
354 x.bar = "hello"
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000355 s = self.dumps(x, 2)
356 y = self.loads(s)
357 self.assertEqual(tuple(x), tuple(y))
358 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000359## import pickletools
360## print
361## pickletools.dis(s)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000362
363 def test_newobj_list(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000364 x = MyList([1, 2, 3])
365 x.foo = 42
366 x.bar = "hello"
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000367 s = self.dumps(x, 2)
368 y = self.loads(s)
369 self.assertEqual(list(x), list(y))
370 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000371## import pickletools
372## print
373## pickletools.dis(s)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000374
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000375 def test_newobj_generic(self):
376 for proto in [0, 1, 2]:
377 for C in myclasses:
378 B = C.__base__
379 x = C(C.sample)
380 x.foo = 42
381 s = self.dumps(x, proto)
382## import pickletools
383## print
384## pickletools.dis(s)
385 y = self.loads(s)
386 detail = (proto, C, B, x, y, type(y))
387 self.assertEqual(B(x), B(y), detail)
388 self.assertEqual(x.__dict__, y.__dict__, detail)
389
Tim Peters47a6b132003-01-28 22:34:11 +0000390# XXX Temporary hack, so long as the C implementation of pickle protocol
391# XXX 2 isn't ready. When it is, move the methods in TempAbstractPickleTests
392# XXX into AbstractPickleTests above, and get rid of TempAbstractPickleTests
393# XXX along with the references to it in test_pickle.py.
394class TempAbstractPickleTests(unittest.TestCase):
395
Guido van Rossumc8d6ef52003-01-28 22:02:31 +0000396 def test_newobj_list_slots(self):
397 x = SlotList([1, 2, 3])
398 x.foo = 42
399 x.bar = "hello"
400 s = self.dumps(x, 2)
401 y = self.loads(s)
402 self.assertEqual(list(x), list(y))
403 self.assertEqual(x.__dict__, y.__dict__)
404 self.assertEqual(x.foo, y.foo)
405 self.assertEqual(x.bar, y.bar)
406## import pickletools
407## print
408## pickletools.dis(s)
409
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000410 def test_global_ext1(self):
411 import copy_reg
412 copy_reg.add_extension(__name__, "MyList", 0xf0)
413 try:
414 x = MyList([1, 2, 3])
415 x.foo = 42
416 x.bar = "hello"
417
418 # Dump using protocol 1 for comparison
419 s1 = self.dumps(x, 1)
420 y = self.loads(s1)
421 self.assertEqual(list(x), list(y))
422 self.assertEqual(x.__dict__, y.__dict__)
423 self.assert_(s1.find(__name__) >= 0)
424 self.assert_(s1.find("MyList") >= 0)
425## import pickletools
426## print
427## pickletools.dis(s1)
428
429 # Dump using protocol 2 for test
430 s2 = self.dumps(x, 2)
431 self.assertEqual(s2.find(__name__), -1)
432 self.assertEqual(s2.find("MyList"), -1)
433 y = self.loads(s2)
434 self.assertEqual(list(x), list(y))
435 self.assertEqual(x.__dict__, y.__dict__)
436## import pickletools
437## print
438## pickletools.dis(s2)
439
440 finally:
441 copy_reg.remove_extension(__name__, "MyList", 0xf0)
442
443 def test_global_ext2(self):
444 import copy_reg
445 copy_reg.add_extension(__name__, "MyList", 0xfff0)
446 try:
447 x = MyList()
448 s2 = self.dumps(x, 2)
449 self.assertEqual(s2.find(__name__), -1)
450 self.assertEqual(s2.find("MyList"), -1)
451 y = self.loads(s2)
452 self.assertEqual(list(x), list(y))
453 self.assertEqual(x.__dict__, y.__dict__)
454 finally:
455 copy_reg.remove_extension(__name__, "MyList", 0xfff0)
456
457 def test_global_ext4(self):
458 import copy_reg
459 copy_reg.add_extension(__name__, "MyList", 0xfffff0)
460 try:
461 x = MyList()
462 s2 = self.dumps(x, 2)
463 self.assertEqual(s2.find(__name__), -1)
464 self.assertEqual(s2.find("MyList"), -1)
465 y = self.loads(s2)
466 self.assertEqual(list(x), list(y))
467 self.assertEqual(x.__dict__, y.__dict__)
468 finally:
469 copy_reg.remove_extension(__name__, "MyList", 0xfffff0)
470
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000471class MyInt(int):
472 sample = 1
473
474class MyLong(long):
475 sample = 1L
476
477class MyFloat(float):
478 sample = 1.0
479
480class MyComplex(complex):
481 sample = 1.0 + 0.0j
482
483class MyStr(str):
484 sample = "hello"
485
486class MyUnicode(unicode):
487 sample = u"hello \u1234"
488
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000489class MyTuple(tuple):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000490 sample = (1, 2, 3)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000491
492class MyList(list):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000493 sample = [1, 2, 3]
494
495class MyDict(dict):
496 sample = {"a": 1, "b": 2}
497
498myclasses = [MyInt, MyLong, MyFloat,
499 # MyComplex, # XXX complex somehow doesn't work here :-(
500 MyStr, MyUnicode,
501 MyTuple, MyList, MyDict]
502
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000503
Guido van Rossumc8d6ef52003-01-28 22:02:31 +0000504class SlotList(MyList):
505 __slots__ = ["foo"]
506
Jeremy Hylton66426532001-10-15 21:38:56 +0000507class AbstractPickleModuleTests(unittest.TestCase):
508
509 def test_dump_closed_file(self):
Guido van Rossum3b0a3292002-08-09 16:38:32 +0000510 import os
511 f = open(TESTFN, "w")
512 try:
513 f.close()
514 self.assertRaises(ValueError, self.module.dump, 123, f)
515 finally:
516 os.remove(TESTFN)
Jeremy Hylton66426532001-10-15 21:38:56 +0000517
518 def test_load_closed_file(self):
Guido van Rossum3b0a3292002-08-09 16:38:32 +0000519 import os
520 f = open(TESTFN, "w")
521 try:
522 f.close()
523 self.assertRaises(ValueError, self.module.dump, 123, f)
524 finally:
525 os.remove(TESTFN)
Jeremy Hylton4c8be852002-11-13 22:10:47 +0000526
527class AbstractPersistentPicklerTests(unittest.TestCase):
528
529 # This class defines persistent_id() and persistent_load()
530 # functions that should be used by the pickler. All even integers
531 # are pickled using persistent ids.
532
533 def persistent_id(self, object):
534 if isinstance(object, int) and object % 2 == 0:
535 self.id_count += 1
536 return str(object)
537 else:
538 return None
539
540 def persistent_load(self, oid):
541 self.load_count += 1
542 object = int(oid)
543 assert object % 2 == 0
544 return object
545
546 def test_persistence(self):
547 self.id_count = 0
548 self.load_count = 0
549 L = range(10)
550 self.assertEqual(self.loads(self.dumps(L)), L)
551 self.assertEqual(self.id_count, 5)
552 self.assertEqual(self.load_count, 5)
553
554 def test_bin_persistence(self):
555 self.id_count = 0
556 self.load_count = 0
557 L = range(10)
558 self.assertEqual(self.loads(self.dumps(L, 1)), L)
559 self.assertEqual(self.id_count, 5)
560 self.assertEqual(self.load_count, 5)