|
1 """Unit tests for the copy module.""" |
|
2 |
|
3 import sys |
|
4 import copy |
|
5 import copy_reg |
|
6 |
|
7 import unittest |
|
8 from test import test_support |
|
9 |
|
10 class TestCopy(unittest.TestCase): |
|
11 |
|
12 # Attempt full line coverage of copy.py from top to bottom |
|
13 |
|
14 def test_exceptions(self): |
|
15 self.assert_(copy.Error is copy.error) |
|
16 self.assert_(issubclass(copy.Error, Exception)) |
|
17 |
|
18 # The copy() method |
|
19 |
|
20 def test_copy_basic(self): |
|
21 x = 42 |
|
22 y = copy.copy(x) |
|
23 self.assertEqual(x, y) |
|
24 |
|
25 def test_copy_copy(self): |
|
26 class C(object): |
|
27 def __init__(self, foo): |
|
28 self.foo = foo |
|
29 def __copy__(self): |
|
30 return C(self.foo) |
|
31 x = C(42) |
|
32 y = copy.copy(x) |
|
33 self.assertEqual(y.__class__, x.__class__) |
|
34 self.assertEqual(y.foo, x.foo) |
|
35 |
|
36 def test_copy_registry(self): |
|
37 class C(object): |
|
38 def __new__(cls, foo): |
|
39 obj = object.__new__(cls) |
|
40 obj.foo = foo |
|
41 return obj |
|
42 def pickle_C(obj): |
|
43 return (C, (obj.foo,)) |
|
44 x = C(42) |
|
45 self.assertRaises(TypeError, copy.copy, x) |
|
46 copy_reg.pickle(C, pickle_C, C) |
|
47 y = copy.copy(x) |
|
48 |
|
49 def test_copy_reduce_ex(self): |
|
50 class C(object): |
|
51 def __reduce_ex__(self, proto): |
|
52 return "" |
|
53 def __reduce__(self): |
|
54 raise test_support.TestFailed, "shouldn't call this" |
|
55 x = C() |
|
56 y = copy.copy(x) |
|
57 self.assert_(y is x) |
|
58 |
|
59 def test_copy_reduce(self): |
|
60 class C(object): |
|
61 def __reduce__(self): |
|
62 return "" |
|
63 x = C() |
|
64 y = copy.copy(x) |
|
65 self.assert_(y is x) |
|
66 |
|
67 def test_copy_cant(self): |
|
68 class C(object): |
|
69 def __getattribute__(self, name): |
|
70 if name.startswith("__reduce"): |
|
71 raise AttributeError, name |
|
72 return object.__getattribute__(self, name) |
|
73 x = C() |
|
74 self.assertRaises(copy.Error, copy.copy, x) |
|
75 |
|
76 # Type-specific _copy_xxx() methods |
|
77 |
|
78 def test_copy_atomic(self): |
|
79 class Classic: |
|
80 pass |
|
81 class NewStyle(object): |
|
82 pass |
|
83 def f(): |
|
84 pass |
|
85 tests = [None, 42, 2L**100, 3.14, True, False, 1j, |
|
86 "hello", u"hello\u1234", f.func_code, |
|
87 NewStyle, xrange(10), Classic, max] |
|
88 for x in tests: |
|
89 self.assert_(copy.copy(x) is x, repr(x)) |
|
90 |
|
91 def test_copy_list(self): |
|
92 x = [1, 2, 3] |
|
93 self.assertEqual(copy.copy(x), x) |
|
94 |
|
95 def test_copy_tuple(self): |
|
96 x = (1, 2, 3) |
|
97 self.assertEqual(copy.copy(x), x) |
|
98 |
|
99 def test_copy_dict(self): |
|
100 x = {"foo": 1, "bar": 2} |
|
101 self.assertEqual(copy.copy(x), x) |
|
102 |
|
103 def test_copy_inst_vanilla(self): |
|
104 class C: |
|
105 def __init__(self, foo): |
|
106 self.foo = foo |
|
107 def __cmp__(self, other): |
|
108 return cmp(self.foo, other.foo) |
|
109 x = C(42) |
|
110 self.assertEqual(copy.copy(x), x) |
|
111 |
|
112 def test_copy_inst_copy(self): |
|
113 class C: |
|
114 def __init__(self, foo): |
|
115 self.foo = foo |
|
116 def __copy__(self): |
|
117 return C(self.foo) |
|
118 def __cmp__(self, other): |
|
119 return cmp(self.foo, other.foo) |
|
120 x = C(42) |
|
121 self.assertEqual(copy.copy(x), x) |
|
122 |
|
123 def test_copy_inst_getinitargs(self): |
|
124 class C: |
|
125 def __init__(self, foo): |
|
126 self.foo = foo |
|
127 def __getinitargs__(self): |
|
128 return (self.foo,) |
|
129 def __cmp__(self, other): |
|
130 return cmp(self.foo, other.foo) |
|
131 x = C(42) |
|
132 self.assertEqual(copy.copy(x), x) |
|
133 |
|
134 def test_copy_inst_getstate(self): |
|
135 class C: |
|
136 def __init__(self, foo): |
|
137 self.foo = foo |
|
138 def __getstate__(self): |
|
139 return {"foo": self.foo} |
|
140 def __cmp__(self, other): |
|
141 return cmp(self.foo, other.foo) |
|
142 x = C(42) |
|
143 self.assertEqual(copy.copy(x), x) |
|
144 |
|
145 def test_copy_inst_setstate(self): |
|
146 class C: |
|
147 def __init__(self, foo): |
|
148 self.foo = foo |
|
149 def __setstate__(self, state): |
|
150 self.foo = state["foo"] |
|
151 def __cmp__(self, other): |
|
152 return cmp(self.foo, other.foo) |
|
153 x = C(42) |
|
154 self.assertEqual(copy.copy(x), x) |
|
155 |
|
156 def test_copy_inst_getstate_setstate(self): |
|
157 class C: |
|
158 def __init__(self, foo): |
|
159 self.foo = foo |
|
160 def __getstate__(self): |
|
161 return self.foo |
|
162 def __setstate__(self, state): |
|
163 self.foo = state |
|
164 def __cmp__(self, other): |
|
165 return cmp(self.foo, other.foo) |
|
166 x = C(42) |
|
167 self.assertEqual(copy.copy(x), x) |
|
168 |
|
169 # The deepcopy() method |
|
170 |
|
171 def test_deepcopy_basic(self): |
|
172 x = 42 |
|
173 y = copy.deepcopy(x) |
|
174 self.assertEqual(y, x) |
|
175 |
|
176 def test_deepcopy_memo(self): |
|
177 # Tests of reflexive objects are under type-specific sections below. |
|
178 # This tests only repetitions of objects. |
|
179 x = [] |
|
180 x = [x, x] |
|
181 y = copy.deepcopy(x) |
|
182 self.assertEqual(y, x) |
|
183 self.assert_(y is not x) |
|
184 self.assert_(y[0] is not x[0]) |
|
185 self.assert_(y[0] is y[1]) |
|
186 |
|
187 def test_deepcopy_issubclass(self): |
|
188 # XXX Note: there's no way to test the TypeError coming out of |
|
189 # issubclass() -- this can only happen when an extension |
|
190 # module defines a "type" that doesn't formally inherit from |
|
191 # type. |
|
192 class Meta(type): |
|
193 pass |
|
194 class C: |
|
195 __metaclass__ = Meta |
|
196 self.assertEqual(copy.deepcopy(C), C) |
|
197 |
|
198 def test_deepcopy_deepcopy(self): |
|
199 class C(object): |
|
200 def __init__(self, foo): |
|
201 self.foo = foo |
|
202 def __deepcopy__(self, memo=None): |
|
203 return C(self.foo) |
|
204 x = C(42) |
|
205 y = copy.deepcopy(x) |
|
206 self.assertEqual(y.__class__, x.__class__) |
|
207 self.assertEqual(y.foo, x.foo) |
|
208 |
|
209 def test_deepcopy_registry(self): |
|
210 class C(object): |
|
211 def __new__(cls, foo): |
|
212 obj = object.__new__(cls) |
|
213 obj.foo = foo |
|
214 return obj |
|
215 def pickle_C(obj): |
|
216 return (C, (obj.foo,)) |
|
217 x = C(42) |
|
218 self.assertRaises(TypeError, copy.deepcopy, x) |
|
219 copy_reg.pickle(C, pickle_C, C) |
|
220 y = copy.deepcopy(x) |
|
221 |
|
222 def test_deepcopy_reduce_ex(self): |
|
223 class C(object): |
|
224 def __reduce_ex__(self, proto): |
|
225 return "" |
|
226 def __reduce__(self): |
|
227 raise test_support.TestFailed, "shouldn't call this" |
|
228 x = C() |
|
229 y = copy.deepcopy(x) |
|
230 self.assert_(y is x) |
|
231 |
|
232 def test_deepcopy_reduce(self): |
|
233 class C(object): |
|
234 def __reduce__(self): |
|
235 return "" |
|
236 x = C() |
|
237 y = copy.deepcopy(x) |
|
238 self.assert_(y is x) |
|
239 |
|
240 def test_deepcopy_cant(self): |
|
241 class C(object): |
|
242 def __getattribute__(self, name): |
|
243 if name.startswith("__reduce"): |
|
244 raise AttributeError, name |
|
245 return object.__getattribute__(self, name) |
|
246 x = C() |
|
247 self.assertRaises(copy.Error, copy.deepcopy, x) |
|
248 |
|
249 # Type-specific _deepcopy_xxx() methods |
|
250 |
|
251 def test_deepcopy_atomic(self): |
|
252 class Classic: |
|
253 pass |
|
254 class NewStyle(object): |
|
255 pass |
|
256 def f(): |
|
257 pass |
|
258 tests = [None, 42, 2L**100, 3.14, True, False, 1j, |
|
259 "hello", u"hello\u1234", f.func_code, |
|
260 NewStyle, xrange(10), Classic, max] |
|
261 for x in tests: |
|
262 self.assert_(copy.deepcopy(x) is x, repr(x)) |
|
263 |
|
264 def test_deepcopy_list(self): |
|
265 x = [[1, 2], 3] |
|
266 y = copy.deepcopy(x) |
|
267 self.assertEqual(y, x) |
|
268 self.assert_(x is not y) |
|
269 self.assert_(x[0] is not y[0]) |
|
270 |
|
271 def test_deepcopy_reflexive_list(self): |
|
272 x = [] |
|
273 x.append(x) |
|
274 y = copy.deepcopy(x) |
|
275 self.assertRaises(RuntimeError, cmp, y, x) |
|
276 self.assert_(y is not x) |
|
277 self.assert_(y[0] is y) |
|
278 self.assertEqual(len(y), 1) |
|
279 |
|
280 def test_deepcopy_tuple(self): |
|
281 x = ([1, 2], 3) |
|
282 y = copy.deepcopy(x) |
|
283 self.assertEqual(y, x) |
|
284 self.assert_(x is not y) |
|
285 self.assert_(x[0] is not y[0]) |
|
286 |
|
287 def test_deepcopy_reflexive_tuple(self): |
|
288 x = ([],) |
|
289 x[0].append(x) |
|
290 y = copy.deepcopy(x) |
|
291 self.assertRaises(RuntimeError, cmp, y, x) |
|
292 self.assert_(y is not x) |
|
293 self.assert_(y[0] is not x[0]) |
|
294 self.assert_(y[0][0] is y) |
|
295 |
|
296 def test_deepcopy_dict(self): |
|
297 x = {"foo": [1, 2], "bar": 3} |
|
298 y = copy.deepcopy(x) |
|
299 self.assertEqual(y, x) |
|
300 self.assert_(x is not y) |
|
301 self.assert_(x["foo"] is not y["foo"]) |
|
302 |
|
303 def test_deepcopy_reflexive_dict(self): |
|
304 x = {} |
|
305 x['foo'] = x |
|
306 y = copy.deepcopy(x) |
|
307 self.assertRaises(RuntimeError, cmp, y, x) |
|
308 self.assert_(y is not x) |
|
309 self.assert_(y['foo'] is y) |
|
310 self.assertEqual(len(y), 1) |
|
311 |
|
312 def test_deepcopy_keepalive(self): |
|
313 memo = {} |
|
314 x = 42 |
|
315 y = copy.deepcopy(x, memo) |
|
316 self.assert_(memo[id(x)] is x) |
|
317 |
|
318 def test_deepcopy_inst_vanilla(self): |
|
319 class C: |
|
320 def __init__(self, foo): |
|
321 self.foo = foo |
|
322 def __cmp__(self, other): |
|
323 return cmp(self.foo, other.foo) |
|
324 x = C([42]) |
|
325 y = copy.deepcopy(x) |
|
326 self.assertEqual(y, x) |
|
327 self.assert_(y.foo is not x.foo) |
|
328 |
|
329 def test_deepcopy_inst_deepcopy(self): |
|
330 class C: |
|
331 def __init__(self, foo): |
|
332 self.foo = foo |
|
333 def __deepcopy__(self, memo): |
|
334 return C(copy.deepcopy(self.foo, memo)) |
|
335 def __cmp__(self, other): |
|
336 return cmp(self.foo, other.foo) |
|
337 x = C([42]) |
|
338 y = copy.deepcopy(x) |
|
339 self.assertEqual(y, x) |
|
340 self.assert_(y is not x) |
|
341 self.assert_(y.foo is not x.foo) |
|
342 |
|
343 def test_deepcopy_inst_getinitargs(self): |
|
344 class C: |
|
345 def __init__(self, foo): |
|
346 self.foo = foo |
|
347 def __getinitargs__(self): |
|
348 return (self.foo,) |
|
349 def __cmp__(self, other): |
|
350 return cmp(self.foo, other.foo) |
|
351 x = C([42]) |
|
352 y = copy.deepcopy(x) |
|
353 self.assertEqual(y, x) |
|
354 self.assert_(y is not x) |
|
355 self.assert_(y.foo is not x.foo) |
|
356 |
|
357 def test_deepcopy_inst_getstate(self): |
|
358 class C: |
|
359 def __init__(self, foo): |
|
360 self.foo = foo |
|
361 def __getstate__(self): |
|
362 return {"foo": self.foo} |
|
363 def __cmp__(self, other): |
|
364 return cmp(self.foo, other.foo) |
|
365 x = C([42]) |
|
366 y = copy.deepcopy(x) |
|
367 self.assertEqual(y, x) |
|
368 self.assert_(y is not x) |
|
369 self.assert_(y.foo is not x.foo) |
|
370 |
|
371 def test_deepcopy_inst_setstate(self): |
|
372 class C: |
|
373 def __init__(self, foo): |
|
374 self.foo = foo |
|
375 def __setstate__(self, state): |
|
376 self.foo = state["foo"] |
|
377 def __cmp__(self, other): |
|
378 return cmp(self.foo, other.foo) |
|
379 x = C([42]) |
|
380 y = copy.deepcopy(x) |
|
381 self.assertEqual(y, x) |
|
382 self.assert_(y is not x) |
|
383 self.assert_(y.foo is not x.foo) |
|
384 |
|
385 def test_deepcopy_inst_getstate_setstate(self): |
|
386 class C: |
|
387 def __init__(self, foo): |
|
388 self.foo = foo |
|
389 def __getstate__(self): |
|
390 return self.foo |
|
391 def __setstate__(self, state): |
|
392 self.foo = state |
|
393 def __cmp__(self, other): |
|
394 return cmp(self.foo, other.foo) |
|
395 x = C([42]) |
|
396 y = copy.deepcopy(x) |
|
397 self.assertEqual(y, x) |
|
398 self.assert_(y is not x) |
|
399 self.assert_(y.foo is not x.foo) |
|
400 |
|
401 def test_deepcopy_reflexive_inst(self): |
|
402 class C: |
|
403 pass |
|
404 x = C() |
|
405 x.foo = x |
|
406 y = copy.deepcopy(x) |
|
407 self.assert_(y is not x) |
|
408 self.assert_(y.foo is y) |
|
409 |
|
410 # _reconstruct() |
|
411 |
|
412 def test_reconstruct_string(self): |
|
413 class C(object): |
|
414 def __reduce__(self): |
|
415 return "" |
|
416 x = C() |
|
417 y = copy.copy(x) |
|
418 self.assert_(y is x) |
|
419 y = copy.deepcopy(x) |
|
420 self.assert_(y is x) |
|
421 |
|
422 def test_reconstruct_nostate(self): |
|
423 class C(object): |
|
424 def __reduce__(self): |
|
425 return (C, ()) |
|
426 x = C() |
|
427 x.foo = 42 |
|
428 y = copy.copy(x) |
|
429 self.assert_(y.__class__ is x.__class__) |
|
430 y = copy.deepcopy(x) |
|
431 self.assert_(y.__class__ is x.__class__) |
|
432 |
|
433 def test_reconstruct_state(self): |
|
434 class C(object): |
|
435 def __reduce__(self): |
|
436 return (C, (), self.__dict__) |
|
437 def __cmp__(self, other): |
|
438 return cmp(self.__dict__, other.__dict__) |
|
439 x = C() |
|
440 x.foo = [42] |
|
441 y = copy.copy(x) |
|
442 self.assertEqual(y, x) |
|
443 y = copy.deepcopy(x) |
|
444 self.assertEqual(y, x) |
|
445 self.assert_(y.foo is not x.foo) |
|
446 |
|
447 def test_reconstruct_state_setstate(self): |
|
448 class C(object): |
|
449 def __reduce__(self): |
|
450 return (C, (), self.__dict__) |
|
451 def __setstate__(self, state): |
|
452 self.__dict__.update(state) |
|
453 def __cmp__(self, other): |
|
454 return cmp(self.__dict__, other.__dict__) |
|
455 x = C() |
|
456 x.foo = [42] |
|
457 y = copy.copy(x) |
|
458 self.assertEqual(y, x) |
|
459 y = copy.deepcopy(x) |
|
460 self.assertEqual(y, x) |
|
461 self.assert_(y.foo is not x.foo) |
|
462 |
|
463 def test_reconstruct_reflexive(self): |
|
464 class C(object): |
|
465 pass |
|
466 x = C() |
|
467 x.foo = x |
|
468 y = copy.deepcopy(x) |
|
469 self.assert_(y is not x) |
|
470 self.assert_(y.foo is y) |
|
471 |
|
472 # Additions for Python 2.3 and pickle protocol 2 |
|
473 |
|
474 def test_reduce_4tuple(self): |
|
475 class C(list): |
|
476 def __reduce__(self): |
|
477 return (C, (), self.__dict__, iter(self)) |
|
478 def __cmp__(self, other): |
|
479 return (cmp(list(self), list(other)) or |
|
480 cmp(self.__dict__, other.__dict__)) |
|
481 x = C([[1, 2], 3]) |
|
482 y = copy.copy(x) |
|
483 self.assertEqual(x, y) |
|
484 self.assert_(x is not y) |
|
485 self.assert_(x[0] is y[0]) |
|
486 y = copy.deepcopy(x) |
|
487 self.assertEqual(x, y) |
|
488 self.assert_(x is not y) |
|
489 self.assert_(x[0] is not y[0]) |
|
490 |
|
491 def test_reduce_5tuple(self): |
|
492 class C(dict): |
|
493 def __reduce__(self): |
|
494 return (C, (), self.__dict__, None, self.iteritems()) |
|
495 def __cmp__(self, other): |
|
496 return (cmp(dict(self), list(dict)) or |
|
497 cmp(self.__dict__, other.__dict__)) |
|
498 x = C([("foo", [1, 2]), ("bar", 3)]) |
|
499 y = copy.copy(x) |
|
500 self.assertEqual(x, y) |
|
501 self.assert_(x is not y) |
|
502 self.assert_(x["foo"] is y["foo"]) |
|
503 y = copy.deepcopy(x) |
|
504 self.assertEqual(x, y) |
|
505 self.assert_(x is not y) |
|
506 self.assert_(x["foo"] is not y["foo"]) |
|
507 |
|
508 def test_copy_slots(self): |
|
509 class C(object): |
|
510 __slots__ = ["foo"] |
|
511 x = C() |
|
512 x.foo = [42] |
|
513 y = copy.copy(x) |
|
514 self.assert_(x.foo is y.foo) |
|
515 |
|
516 def test_deepcopy_slots(self): |
|
517 class C(object): |
|
518 __slots__ = ["foo"] |
|
519 x = C() |
|
520 x.foo = [42] |
|
521 y = copy.deepcopy(x) |
|
522 self.assertEqual(x.foo, y.foo) |
|
523 self.assert_(x.foo is not y.foo) |
|
524 |
|
525 def test_copy_list_subclass(self): |
|
526 class C(list): |
|
527 pass |
|
528 x = C([[1, 2], 3]) |
|
529 x.foo = [4, 5] |
|
530 y = copy.copy(x) |
|
531 self.assertEqual(list(x), list(y)) |
|
532 self.assertEqual(x.foo, y.foo) |
|
533 self.assert_(x[0] is y[0]) |
|
534 self.assert_(x.foo is y.foo) |
|
535 |
|
536 def test_deepcopy_list_subclass(self): |
|
537 class C(list): |
|
538 pass |
|
539 x = C([[1, 2], 3]) |
|
540 x.foo = [4, 5] |
|
541 y = copy.deepcopy(x) |
|
542 self.assertEqual(list(x), list(y)) |
|
543 self.assertEqual(x.foo, y.foo) |
|
544 self.assert_(x[0] is not y[0]) |
|
545 self.assert_(x.foo is not y.foo) |
|
546 |
|
547 def test_copy_tuple_subclass(self): |
|
548 class C(tuple): |
|
549 pass |
|
550 x = C([1, 2, 3]) |
|
551 self.assertEqual(tuple(x), (1, 2, 3)) |
|
552 y = copy.copy(x) |
|
553 self.assertEqual(tuple(y), (1, 2, 3)) |
|
554 |
|
555 def test_deepcopy_tuple_subclass(self): |
|
556 class C(tuple): |
|
557 pass |
|
558 x = C([[1, 2], 3]) |
|
559 self.assertEqual(tuple(x), ([1, 2], 3)) |
|
560 y = copy.deepcopy(x) |
|
561 self.assertEqual(tuple(y), ([1, 2], 3)) |
|
562 self.assert_(x is not y) |
|
563 self.assert_(x[0] is not y[0]) |
|
564 |
|
565 def test_getstate_exc(self): |
|
566 class EvilState(object): |
|
567 def __getstate__(self): |
|
568 raise ValueError, "ain't got no stickin' state" |
|
569 self.assertRaises(ValueError, copy.copy, EvilState()) |
|
570 |
|
571 def test_copy_function(self): |
|
572 self.assertEqual(copy.copy(global_foo), global_foo) |
|
573 def foo(x, y): return x+y |
|
574 self.assertEqual(copy.copy(foo), foo) |
|
575 bar = lambda: None |
|
576 self.assertEqual(copy.copy(bar), bar) |
|
577 |
|
578 def test_deepcopy_function(self): |
|
579 self.assertEqual(copy.deepcopy(global_foo), global_foo) |
|
580 def foo(x, y): return x+y |
|
581 self.assertEqual(copy.deepcopy(foo), foo) |
|
582 bar = lambda: None |
|
583 self.assertEqual(copy.deepcopy(bar), bar) |
|
584 |
|
585 def global_foo(x, y): return x+y |
|
586 |
|
587 def test_main(): |
|
588 test_support.run_unittest(TestCopy) |
|
589 |
|
590 if __name__ == "__main__": |
|
591 test_main() |