blob: dbecddc4978fa1fd36e048c8175b55ebc627a2d8 [file] [log] [blame]
Jeremy Hylton66426532001-10-15 21:38:56 +00001import unittest
Tim Peters4190fb82003-02-02 16:09:05 +00002import pickle
Tim Peters31f119e2003-02-03 16:20:13 +00003import pickletools
Tim Peters4190fb82003-02-02 16:09:05 +00004
Guido van Rossum3b0a3292002-08-09 16:38:32 +00005from test.test_support import TestFailed, have_unicode, TESTFN
Tim Peterse089c682001-04-10 03:41:41 +00006
Tim Petersee1a53c2003-02-02 02:57:53 +00007# Tests that try a number of pickle protocols should have a
8# for proto in protocols:
9# kind of outer loop. Bump the 3 to 4 if/when protocol 3 is invented.
10protocols = range(3)
11
Jeremy Hylton66426532001-10-15 21:38:56 +000012class C:
13 def __cmp__(self, other):
14 return cmp(self.__dict__, other.__dict__)
15
16import __main__
17__main__.C = C
18C.__module__ = "__main__"
19
20class myint(int):
21 def __init__(self, x):
22 self.str = str(x)
23
24class initarg(C):
Guido van Rossum1444f672001-12-19 16:38:29 +000025
Jeremy Hylton66426532001-10-15 21:38:56 +000026 def __init__(self, a, b):
27 self.a = a
28 self.b = b
29
30 def __getinitargs__(self):
31 return self.a, self.b
32
Guido van Rossum04a86612001-12-19 16:58:54 +000033class metaclass(type):
34 pass
35
36class use_metaclass(object):
37 __metaclass__ = metaclass
38
Tim Peters70b02d72003-02-02 17:26:40 +000039# DATA0 .. DATA2 are the pickles we expect under the various protocols, for
40# the object returned by create_data().
41# XXX DATA2 doesn't exist yet, as it's not fully implemented in cPickle.
Tim Petersee1a53c2003-02-02 02:57:53 +000042
Jeremy Hylton66426532001-10-15 21:38:56 +000043# break into multiple strings to avoid confusing font-lock-mode
Tim Peters70b02d72003-02-02 17:26:40 +000044DATA0 = """(lp1
Tim Peterse9358162001-01-22 22:05:20 +000045I0
46aL1L
Tim Peters461922a2001-04-09 20:07:05 +000047aF2
Tim Peterse9358162001-01-22 22:05:20 +000048ac__builtin__
49complex
Tim Peters461922a2001-04-09 20:07:05 +000050p2
51""" + \
52"""(F3
53F0
54tRp3
55aI1
56aI-1
57aI255
58aI-255
59aI-256
60aI65535
61aI-65535
62aI-65536
63aI2147483647
64aI-2147483647
65aI-2147483648
66a""" + \
67"""(S'abc'
Tim Peterse9358162001-01-22 22:05:20 +000068p4
69g4
Tim Peters461922a2001-04-09 20:07:05 +000070""" + \
Guido van Rossum42f92da2001-04-16 00:28:21 +000071"""(i__main__
Tim Peterse9358162001-01-22 22:05:20 +000072C
73p5
Tim Peters461922a2001-04-09 20:07:05 +000074""" + \
Tim Peterse9358162001-01-22 22:05:20 +000075"""(dp6
76S'foo'
77p7
78I1
79sS'bar'
80p8
81I2
82sbg5
83tp9
84ag9
85aI5
86a.
87"""
88
Tim Peters70b02d72003-02-02 17:26:40 +000089# Disassembly of DATA0.
90DATA0_DIS = """\
91 0: ( MARK
92 1: l LIST (MARK at 0)
93 2: p PUT 1
94 5: I INT 0
95 8: a APPEND
96 9: L LONG 1L
97 13: a APPEND
98 14: F FLOAT 2.0
99 17: a APPEND
100 18: c GLOBAL '__builtin__ complex'
101 39: p PUT 2
102 42: ( MARK
103 43: F FLOAT 3.0
104 46: F FLOAT 0.0
105 49: t TUPLE (MARK at 42)
106 50: R REDUCE
107 51: p PUT 3
108 54: a APPEND
109 55: I INT 1
110 58: a APPEND
111 59: I INT -1
112 63: a APPEND
113 64: I INT 255
114 69: a APPEND
115 70: I INT -255
116 76: a APPEND
117 77: I INT -256
118 83: a APPEND
119 84: I INT 65535
120 91: a APPEND
121 92: I INT -65535
122 100: a APPEND
123 101: I INT -65536
124 109: a APPEND
125 110: I INT 2147483647
126 122: a APPEND
127 123: I INT -2147483647
128 136: a APPEND
129 137: I INT -2147483648
130 150: a APPEND
131 151: ( MARK
132 152: S STRING 'abc'
133 159: p PUT 4
134 162: g GET 4
135 165: ( MARK
136 166: i INST '__main__ C' (MARK at 165)
137 178: p PUT 5
138 181: ( MARK
139 182: d DICT (MARK at 181)
140 183: p PUT 6
141 186: S STRING 'foo'
142 193: p PUT 7
143 196: I INT 1
144 199: s SETITEM
145 200: S STRING 'bar'
146 207: p PUT 8
147 210: I INT 2
148 213: s SETITEM
149 214: b BUILD
150 215: g GET 5
151 218: t TUPLE (MARK at 151)
152 219: p PUT 9
153 222: a APPEND
154 223: g GET 9
155 226: a APPEND
156 227: I INT 5
157 230: a APPEND
158 231: . STOP
159highest protocol among opcodes = 0
160"""
161
162DATA1 = (']q\x01(K\x00L1L\nG@\x00\x00\x00\x00\x00\x00\x00'
163 'c__builtin__\ncomplex\nq\x02(G@\x08\x00\x00\x00\x00\x00'
164 '\x00G\x00\x00\x00\x00\x00\x00\x00\x00tRq\x03K\x01J\xff\xff'
165 '\xff\xffK\xffJ\x01\xff\xff\xffJ\x00\xff\xff\xffM\xff\xff'
166 'J\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff\xff\xff\x7fJ\x01\x00'
167 '\x00\x80J\x00\x00\x00\x80(U\x03abcq\x04h\x04(c__main__\n'
168 'C\nq\x05oq\x06}q\x07(U\x03fooq\x08K\x01U\x03barq\tK\x02ubh'
169 '\x06tq\nh\nK\x05e.'
170 )
171
172# Disassembly of DATA1.
173DATA1_DIS = """\
174 0: ] EMPTY_LIST
175 1: q BINPUT 1
176 3: ( MARK
177 4: K BININT1 0
178 6: L LONG 1L
179 10: G BINFLOAT 2.0
180 19: c GLOBAL '__builtin__ complex'
181 40: q BINPUT 2
182 42: ( MARK
183 43: G BINFLOAT 3.0
184 52: G BINFLOAT 0.0
185 61: t TUPLE (MARK at 42)
186 62: R REDUCE
187 63: q BINPUT 3
188 65: K BININT1 1
189 67: J BININT -1
190 72: K BININT1 255
191 74: J BININT -255
192 79: J BININT -256
193 84: M BININT2 65535
194 87: J BININT -65535
195 92: J BININT -65536
196 97: J BININT 2147483647
197 102: J BININT -2147483647
198 107: J BININT -2147483648
199 112: ( MARK
200 113: U SHORT_BINSTRING 'abc'
201 118: q BINPUT 4
202 120: h BINGET 4
203 122: ( MARK
204 123: c GLOBAL '__main__ C'
205 135: q BINPUT 5
206 137: o OBJ (MARK at 122)
207 138: q BINPUT 6
208 140: } EMPTY_DICT
209 141: q BINPUT 7
210 143: ( MARK
211 144: U SHORT_BINSTRING 'foo'
212 149: q BINPUT 8
213 151: K BININT1 1
214 153: U SHORT_BINSTRING 'bar'
215 158: q BINPUT 9
216 160: K BININT1 2
217 162: u SETITEMS (MARK at 143)
218 163: b BUILD
219 164: h BINGET 6
220 166: t TUPLE (MARK at 112)
221 167: q BINPUT 10
222 169: h BINGET 10
223 171: K BININT1 5
224 173: e APPENDS (MARK at 3)
225 174: . STOP
226highest protocol among opcodes = 1
227"""
Tim Peterse0c446b2001-10-18 21:57:37 +0000228
Jeremy Hylton66426532001-10-15 21:38:56 +0000229def create_data():
Tim Peterse9358162001-01-22 22:05:20 +0000230 c = C()
231 c.foo = 1
232 c.bar = 2
233 x = [0, 1L, 2.0, 3.0+0j]
Tim Peters461922a2001-04-09 20:07:05 +0000234 # Append some integer test cases at cPickle.c's internal size
235 # cutoffs.
236 uint1max = 0xff
237 uint2max = 0xffff
238 int4max = 0x7fffffff
239 x.extend([1, -1,
240 uint1max, -uint1max, -uint1max-1,
241 uint2max, -uint2max, -uint2max-1,
242 int4max, -int4max, -int4max-1])
Tim Peterse9358162001-01-22 22:05:20 +0000243 y = ('abc', 'abc', c, c)
244 x.append(y)
245 x.append(y)
246 x.append(5)
Jeremy Hylton66426532001-10-15 21:38:56 +0000247 return x
Tim Petersc58440f2001-04-09 17:16:31 +0000248
Jeremy Hylton66426532001-10-15 21:38:56 +0000249class AbstractPickleTests(unittest.TestCase):
Tim Peters70b02d72003-02-02 17:26:40 +0000250 # Subclass must define self.dumps, self.loads, self.error.
Tim Petersc58440f2001-04-09 17:16:31 +0000251
Jeremy Hylton66426532001-10-15 21:38:56 +0000252 _testdata = create_data()
Tim Petersc58440f2001-04-09 17:16:31 +0000253
Jeremy Hylton66426532001-10-15 21:38:56 +0000254 def setUp(self):
Tim Peterse9358162001-01-22 22:05:20 +0000255 pass
Tim Petersc58440f2001-04-09 17:16:31 +0000256
Tim Peters31f119e2003-02-03 16:20:13 +0000257 def ensure_opcode_in_pickle(self, code, pickle):
258 for op, dummy, dummy in pickletools.genops(pickle):
259 if op.code == code:
260 return
261 self.fail("didn't find opcode %r in pickle %r" % (code, pickle))
262
Jeremy Hylton66426532001-10-15 21:38:56 +0000263 def test_misc(self):
264 # test various datatypes not tested by testdata
Tim Peters70b02d72003-02-02 17:26:40 +0000265 for proto in protocols:
266 x = myint(4)
267 s = self.dumps(x, proto)
268 y = self.loads(s)
269 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000270
Tim Peters70b02d72003-02-02 17:26:40 +0000271 x = (1, ())
272 s = self.dumps(x, proto)
273 y = self.loads(s)
274 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000275
Tim Peters70b02d72003-02-02 17:26:40 +0000276 x = initarg(1, x)
277 s = self.dumps(x, proto)
278 y = self.loads(s)
279 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000280
Jeremy Hylton66426532001-10-15 21:38:56 +0000281 # XXX test __reduce__ protocol?
282
Tim Peters70b02d72003-02-02 17:26:40 +0000283 def test_roundtrip_equality(self):
284 expected = self._testdata
285 for proto in protocols:
286 s = self.dumps(expected, proto)
287 got = self.loads(s)
288 self.assertEqual(expected, got)
Jeremy Hylton66426532001-10-15 21:38:56 +0000289
Tim Peters70b02d72003-02-02 17:26:40 +0000290 def test_load_from_canned_string(self):
291 expected = self._testdata
292 for canned in DATA0, DATA1:
293 got = self.loads(canned)
294 self.assertEqual(expected, got)
Jeremy Hylton66426532001-10-15 21:38:56 +0000295
Tim Peters70b02d72003-02-02 17:26:40 +0000296 # There are gratuitous differences between pickles produced by
297 # pickle and cPickle, largely because cPickle starts PUT indices at
298 # 1 and pickle starts them at 0. See XXX comment in cPickle's put2() --
299 # there's a comment with an exclamation point there whose meaning
300 # is a mystery. cPickle also suppresses PUT for objects with a refcount
301 # of 1.
302 def dont_test_disassembly(self):
303 from cStringIO import StringIO
304 from pickletools import dis
305
306 for proto, expected in (0, DATA0_DIS), (1, DATA1_DIS):
307 s = self.dumps(self._testdata, proto)
308 filelike = StringIO()
309 dis(s, out=filelike)
310 got = filelike.getvalue()
311 self.assertEqual(expected, got)
Jeremy Hylton66426532001-10-15 21:38:56 +0000312
313 def test_recursive_list(self):
314 l = []
315 l.append(l)
Tim Peters70b02d72003-02-02 17:26:40 +0000316 for proto in protocols:
317 s = self.dumps(l, proto)
318 x = self.loads(s)
319 self.assertEqual(x, l)
320 self.assertEqual(x, x[0])
321 self.assertEqual(id(x), id(x[0]))
Jeremy Hylton66426532001-10-15 21:38:56 +0000322
323 def test_recursive_dict(self):
324 d = {}
325 d[1] = d
Tim Peters70b02d72003-02-02 17:26:40 +0000326 for proto in protocols:
327 s = self.dumps(d, proto)
328 x = self.loads(s)
329 self.assertEqual(x, d)
330 self.assertEqual(x[1], x)
331 self.assertEqual(id(x[1]), id(x))
Jeremy Hylton66426532001-10-15 21:38:56 +0000332
333 def test_recursive_inst(self):
334 i = C()
335 i.attr = i
Tim Peters70b02d72003-02-02 17:26:40 +0000336 for proto in protocols:
337 s = self.dumps(i, 2)
338 x = self.loads(s)
339 self.assertEqual(x, i)
340 self.assertEqual(x.attr, x)
341 self.assertEqual(id(x.attr), id(x))
Jeremy Hylton66426532001-10-15 21:38:56 +0000342
343 def test_recursive_multi(self):
344 l = []
345 d = {1:l}
346 i = C()
347 i.attr = d
348 l.append(i)
Tim Peters70b02d72003-02-02 17:26:40 +0000349 for proto in protocols:
350 s = self.dumps(l, proto)
351 x = self.loads(s)
352 self.assertEqual(x, l)
353 self.assertEqual(x[0], i)
354 self.assertEqual(x[0].attr, d)
355 self.assertEqual(x[0].attr[1], x)
356 self.assertEqual(x[0].attr[1][0], i)
357 self.assertEqual(x[0].attr[1][0].attr, d)
Jeremy Hylton66426532001-10-15 21:38:56 +0000358
359 def test_garyp(self):
360 self.assertRaises(self.error, self.loads, 'garyp')
361
362 def test_insecure_strings(self):
363 insecure = ["abc", "2 + 2", # not quoted
Martin v. Löwis8a8da792002-08-14 07:46:28 +0000364 #"'abc' + 'def'", # not a single quoted string
Jeremy Hylton66426532001-10-15 21:38:56 +0000365 "'abc", # quote is not closed
366 "'abc\"", # open quote and close quote don't match
367 "'abc' ?", # junk after close quote
Martin v. Löwiseb3f00a2002-08-14 08:22:50 +0000368 "'\\'", # trailing backslash
Jeremy Hylton66426532001-10-15 21:38:56 +0000369 # some tests of the quoting rules
Martin v. Löwis8a8da792002-08-14 07:46:28 +0000370 #"'abc\"\''",
371 #"'\\\\a\'\'\'\\\'\\\\\''",
Jeremy Hylton66426532001-10-15 21:38:56 +0000372 ]
373 for s in insecure:
374 buf = "S" + s + "\012p0\012."
375 self.assertRaises(ValueError, self.loads, buf)
376
Martin v. Löwis339d0f72001-08-17 18:39:25 +0000377 if have_unicode:
Jeremy Hylton66426532001-10-15 21:38:56 +0000378 def test_unicode(self):
379 endcases = [unicode(''), unicode('<\\u>'), unicode('<\\\u1234>'),
380 unicode('<\n>'), unicode('<\\>')]
Tim Petersee1a53c2003-02-02 02:57:53 +0000381 for proto in protocols:
382 for u in endcases:
383 p = self.dumps(u, proto)
384 u2 = self.loads(p)
385 self.assertEqual(u2, u)
Tim Peterse089c682001-04-10 03:41:41 +0000386
Jeremy Hylton66426532001-10-15 21:38:56 +0000387 def test_ints(self):
388 import sys
Tim Petersee1a53c2003-02-02 02:57:53 +0000389 for proto in protocols:
390 n = sys.maxint
391 while n:
392 for expected in (-n, n):
393 s = self.dumps(expected, proto)
394 n2 = self.loads(s)
395 self.assertEqual(expected, n2)
396 n = n >> 1
Tim Peters19ef62d2001-08-28 22:21:18 +0000397
Jeremy Hylton66426532001-10-15 21:38:56 +0000398 def test_maxint64(self):
399 maxint64 = (1L << 63) - 1
400 data = 'I' + str(maxint64) + '\n.'
401 got = self.loads(data)
402 self.assertEqual(got, maxint64)
403
404 # Try too with a bogus literal.
405 data = 'I' + str(maxint64) + 'JUNK\n.'
406 self.assertRaises(ValueError, self.loads, data)
407
Tim Petersee1a53c2003-02-02 02:57:53 +0000408 def test_long(self):
409 for proto in protocols:
Tim Petersbf2674b2003-02-02 07:51:32 +0000410 # 256 bytes is where LONG4 begins.
Tim Petersee1a53c2003-02-02 02:57:53 +0000411 for nbits in 1, 8, 8*254, 8*255, 8*256, 8*257:
412 nbase = 1L << nbits
413 for npos in nbase-1, nbase, nbase+1:
414 for n in npos, -npos:
415 pickle = self.dumps(n, proto)
416 got = self.loads(pickle)
417 self.assertEqual(n, got)
418 # Try a monster. This is quadratic-time in protos 0 & 1, so don't
419 # bother with those.
Tim Petersee1a53c2003-02-02 02:57:53 +0000420 nbase = long("deadbeeffeedface", 16)
421 nbase += nbase << 1000000
422 for n in nbase, -nbase:
Tim Petersee1a53c2003-02-02 02:57:53 +0000423 p = self.dumps(n, 2)
Tim Petersee1a53c2003-02-02 02:57:53 +0000424 got = self.loads(p)
Tim Petersee1a53c2003-02-02 02:57:53 +0000425 self.assertEqual(n, got)
426
Jeremy Hylton66426532001-10-15 21:38:56 +0000427 def test_reduce(self):
Tim Peters19ef62d2001-08-28 22:21:18 +0000428 pass
Jeremy Hylton66426532001-10-15 21:38:56 +0000429
430 def test_getinitargs(self):
431 pass
432
Guido van Rossum04a86612001-12-19 16:58:54 +0000433 def test_metaclass(self):
434 a = use_metaclass()
Tim Peters70b02d72003-02-02 17:26:40 +0000435 for proto in protocols:
436 s = self.dumps(a, proto)
437 b = self.loads(s)
438 self.assertEqual(a.__class__, b.__class__)
Guido van Rossum04a86612001-12-19 16:58:54 +0000439
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000440 def test_structseq(self):
441 import time
Michael W. Hudson0e025302002-03-06 17:11:18 +0000442 import os
Tim Peters70b02d72003-02-02 17:26:40 +0000443
444 t = time.localtime()
445 for proto in protocols:
446 s = self.dumps(t, proto)
Michael W. Hudson0e025302002-03-06 17:11:18 +0000447 u = self.loads(s)
448 self.assertEqual(t, u)
Tim Peters70b02d72003-02-02 17:26:40 +0000449 if hasattr(os, "stat"):
450 t = os.stat(os.curdir)
451 s = self.dumps(t, proto)
452 u = self.loads(s)
453 self.assertEqual(t, u)
454 if hasattr(os, "statvfs"):
455 t = os.statvfs(os.curdir)
456 s = self.dumps(t, proto)
457 u = self.loads(s)
458 self.assertEqual(t, u)
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000459
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000460 # Tests for protocol 2
461
Tim Peters4190fb82003-02-02 16:09:05 +0000462 def test_proto(self):
463 build_none = pickle.NONE + pickle.STOP
464 for proto in protocols:
465 expected = build_none
466 if proto >= 2:
467 expected = pickle.PROTO + chr(proto) + expected
468 p = self.dumps(None, proto)
469 self.assertEqual(p, expected)
470
471 oob = protocols[-1] + 1 # a future protocol
472 badpickle = pickle.PROTO + chr(oob) + build_none
473 try:
474 self.loads(badpickle)
475 except ValueError, detail:
476 self.failUnless(str(detail).startswith(
477 "unsupported pickle protocol"))
478 else:
479 self.fail("expected bad protocol number to raise ValueError")
480
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000481 def test_long1(self):
482 x = 12345678910111213141516178920L
483 s = self.dumps(x, 2)
484 y = self.loads(s)
485 self.assertEqual(x, y)
Tim Peters31f119e2003-02-03 16:20:13 +0000486 self.ensure_opcode_in_pickle(pickle.LONG1, s)
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000487
488 def test_long4(self):
489 x = 12345678910111213141516178920L << (256*8)
490 s = self.dumps(x, 2)
491 y = self.loads(s)
492 self.assertEqual(x, y)
Tim Peters31f119e2003-02-03 16:20:13 +0000493 self.ensure_opcode_in_pickle(pickle.LONG4, s)
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000494
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000495 def test_short_tuples(self):
Tim Peters1d63c9f2003-02-02 20:29:39 +0000496 # Map (proto, len(tuple)) to expected opcode.
497 expected_opcode = {(0, 0): pickle.TUPLE,
498 (0, 1): pickle.TUPLE,
499 (0, 2): pickle.TUPLE,
500 (0, 3): pickle.TUPLE,
501 (0, 4): pickle.TUPLE,
502
503 (1, 0): pickle.EMPTY_TUPLE,
504 (1, 1): pickle.TUPLE,
505 (1, 2): pickle.TUPLE,
506 (1, 3): pickle.TUPLE,
507 (1, 4): pickle.TUPLE,
508
509 (2, 0): pickle.EMPTY_TUPLE,
510 (2, 1): pickle.TUPLE1,
511 (2, 2): pickle.TUPLE2,
512 (2, 3): pickle.TUPLE3,
513 (2, 4): pickle.TUPLE,
514 }
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000515 a = ()
Guido van Rossum025bc2f2003-01-28 04:20:02 +0000516 b = (1,)
517 c = (1, 2)
518 d = (1, 2, 3)
519 e = (1, 2, 3, 4)
Tim Peters4190fb82003-02-02 16:09:05 +0000520 for proto in protocols:
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000521 for x in a, b, c, d, e:
522 s = self.dumps(x, proto)
523 y = self.loads(s)
524 self.assertEqual(x, y, (proto, x, s, y))
Tim Peters1d63c9f2003-02-02 20:29:39 +0000525 expected = expected_opcode[proto, len(x)]
Tim Peters31f119e2003-02-03 16:20:13 +0000526 self.ensure_opcode_in_pickle(expected, s)
Tim Peters1d63c9f2003-02-02 20:29:39 +0000527
Guido van Rossum7d97d312003-01-28 04:25:27 +0000528 def test_singletons(self):
Tim Peters4190fb82003-02-02 16:09:05 +0000529 for proto in protocols:
Guido van Rossum7d97d312003-01-28 04:25:27 +0000530 for x in None, False, True:
531 s = self.dumps(x, proto)
532 y = self.loads(s)
533 self.assert_(x is y, (proto, x, s, y))
534
Tim Peters3c67d792003-02-02 17:59:11 +0000535 # Test that proto >= 2 really uses the bool opcodes.
536 if proto >= 2 and x in (False, True):
537 expected = x and pickle.NEWTRUE or pickle.NEWFALSE
538 # Skip the PROTO opcode at the start.
539 self.assertEqual(s[2], expected)
540
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000541 def test_newobj_tuple(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000542 x = MyTuple([1, 2, 3])
543 x.foo = 42
544 x.bar = "hello"
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000545 s = self.dumps(x, 2)
546 y = self.loads(s)
547 self.assertEqual(tuple(x), tuple(y))
548 self.assertEqual(x.__dict__, y.__dict__)
549
550 def test_newobj_list(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000551 x = MyList([1, 2, 3])
552 x.foo = 42
553 x.bar = "hello"
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000554 s = self.dumps(x, 2)
555 y = self.loads(s)
556 self.assertEqual(list(x), list(y))
557 self.assertEqual(x.__dict__, y.__dict__)
558
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000559 def test_newobj_generic(self):
560 for proto in [0, 1, 2]:
561 for C in myclasses:
562 B = C.__base__
563 x = C(C.sample)
564 x.foo = 42
565 s = self.dumps(x, proto)
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000566 y = self.loads(s)
567 detail = (proto, C, B, x, y, type(y))
568 self.assertEqual(B(x), B(y), detail)
569 self.assertEqual(x.__dict__, y.__dict__, detail)
570
Tim Peters47a6b132003-01-28 22:34:11 +0000571# XXX Temporary hack, so long as the C implementation of pickle protocol
572# XXX 2 isn't ready. When it is, move the methods in TempAbstractPickleTests
573# XXX into AbstractPickleTests above, and get rid of TempAbstractPickleTests
574# XXX along with the references to it in test_pickle.py.
575class TempAbstractPickleTests(unittest.TestCase):
576
Guido van Rossumc8d6ef52003-01-28 22:02:31 +0000577 def test_newobj_list_slots(self):
578 x = SlotList([1, 2, 3])
579 x.foo = 42
580 x.bar = "hello"
581 s = self.dumps(x, 2)
582 y = self.loads(s)
583 self.assertEqual(list(x), list(y))
584 self.assertEqual(x.__dict__, y.__dict__)
585 self.assertEqual(x.foo, y.foo)
586 self.assertEqual(x.bar, y.bar)
587## import pickletools
588## print
589## pickletools.dis(s)
590
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000591 def test_global_ext1(self):
592 import copy_reg
593 copy_reg.add_extension(__name__, "MyList", 0xf0)
594 try:
595 x = MyList([1, 2, 3])
596 x.foo = 42
597 x.bar = "hello"
598
599 # Dump using protocol 1 for comparison
600 s1 = self.dumps(x, 1)
601 y = self.loads(s1)
602 self.assertEqual(list(x), list(y))
603 self.assertEqual(x.__dict__, y.__dict__)
604 self.assert_(s1.find(__name__) >= 0)
605 self.assert_(s1.find("MyList") >= 0)
606## import pickletools
607## print
608## pickletools.dis(s1)
609
610 # Dump using protocol 2 for test
611 s2 = self.dumps(x, 2)
612 self.assertEqual(s2.find(__name__), -1)
613 self.assertEqual(s2.find("MyList"), -1)
614 y = self.loads(s2)
615 self.assertEqual(list(x), list(y))
616 self.assertEqual(x.__dict__, y.__dict__)
617## import pickletools
618## print
619## pickletools.dis(s2)
620
621 finally:
622 copy_reg.remove_extension(__name__, "MyList", 0xf0)
623
624 def test_global_ext2(self):
625 import copy_reg
626 copy_reg.add_extension(__name__, "MyList", 0xfff0)
627 try:
628 x = MyList()
629 s2 = self.dumps(x, 2)
630 self.assertEqual(s2.find(__name__), -1)
631 self.assertEqual(s2.find("MyList"), -1)
632 y = self.loads(s2)
633 self.assertEqual(list(x), list(y))
634 self.assertEqual(x.__dict__, y.__dict__)
635 finally:
636 copy_reg.remove_extension(__name__, "MyList", 0xfff0)
637
638 def test_global_ext4(self):
639 import copy_reg
640 copy_reg.add_extension(__name__, "MyList", 0xfffff0)
641 try:
642 x = MyList()
643 s2 = self.dumps(x, 2)
644 self.assertEqual(s2.find(__name__), -1)
645 self.assertEqual(s2.find("MyList"), -1)
646 y = self.loads(s2)
647 self.assertEqual(list(x), list(y))
648 self.assertEqual(x.__dict__, y.__dict__)
649 finally:
650 copy_reg.remove_extension(__name__, "MyList", 0xfffff0)
651
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000652class MyInt(int):
653 sample = 1
654
655class MyLong(long):
656 sample = 1L
657
658class MyFloat(float):
659 sample = 1.0
660
661class MyComplex(complex):
662 sample = 1.0 + 0.0j
663
664class MyStr(str):
665 sample = "hello"
666
667class MyUnicode(unicode):
668 sample = u"hello \u1234"
669
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000670class MyTuple(tuple):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000671 sample = (1, 2, 3)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000672
673class MyList(list):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000674 sample = [1, 2, 3]
675
676class MyDict(dict):
677 sample = {"a": 1, "b": 2}
678
679myclasses = [MyInt, MyLong, MyFloat,
680 # MyComplex, # XXX complex somehow doesn't work here :-(
681 MyStr, MyUnicode,
682 MyTuple, MyList, MyDict]
683
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000684
Guido van Rossumc8d6ef52003-01-28 22:02:31 +0000685class SlotList(MyList):
686 __slots__ = ["foo"]
687
Jeremy Hylton66426532001-10-15 21:38:56 +0000688class AbstractPickleModuleTests(unittest.TestCase):
689
690 def test_dump_closed_file(self):
Guido van Rossum3b0a3292002-08-09 16:38:32 +0000691 import os
692 f = open(TESTFN, "w")
693 try:
694 f.close()
695 self.assertRaises(ValueError, self.module.dump, 123, f)
696 finally:
697 os.remove(TESTFN)
Jeremy Hylton66426532001-10-15 21:38:56 +0000698
699 def test_load_closed_file(self):
Guido van Rossum3b0a3292002-08-09 16:38:32 +0000700 import os
701 f = open(TESTFN, "w")
702 try:
703 f.close()
704 self.assertRaises(ValueError, self.module.dump, 123, f)
705 finally:
706 os.remove(TESTFN)
Jeremy Hylton4c8be852002-11-13 22:10:47 +0000707
708class AbstractPersistentPicklerTests(unittest.TestCase):
709
710 # This class defines persistent_id() and persistent_load()
711 # functions that should be used by the pickler. All even integers
712 # are pickled using persistent ids.
713
714 def persistent_id(self, object):
715 if isinstance(object, int) and object % 2 == 0:
716 self.id_count += 1
717 return str(object)
718 else:
719 return None
720
721 def persistent_load(self, oid):
722 self.load_count += 1
723 object = int(oid)
724 assert object % 2 == 0
725 return object
726
727 def test_persistence(self):
728 self.id_count = 0
729 self.load_count = 0
730 L = range(10)
731 self.assertEqual(self.loads(self.dumps(L)), L)
732 self.assertEqual(self.id_count, 5)
733 self.assertEqual(self.load_count, 5)
734
735 def test_bin_persistence(self):
736 self.id_count = 0
737 self.load_count = 0
738 L = range(10)
739 self.assertEqual(self.loads(self.dumps(L, 1)), L)
740 self.assertEqual(self.id_count, 5)
741 self.assertEqual(self.load_count, 5)