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