test_copy.py revision 3941a8fece7e714583965565795f2986aa203cb1
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_deepcopy_dict_subclass(self):
536        class C(dict):
537            def __init__(self, d=None):
538                if not d:
539                    d = {}
540                self._keys = list(d.keys())
541                super().__init__(d)
542            def __setitem__(self, key, item):
543                super().__setitem__(key, item)
544                if key not in self._keys:
545                    self._keys.append(key)
546        x = C(d={'foo':0})
547        y = copy.deepcopy(x)
548        self.assertEqual(x, y)
549        self.assertEqual(x._keys, y._keys)
550        self.assertTrue(x is not y)
551        x['bar'] = 1
552        self.assertNotEqual(x, y)
553        self.assertNotEqual(x._keys, y._keys)
554
555    def test_copy_list_subclass(self):
556        class C(list):
557            pass
558        x = C([[1, 2], 3])
559        x.foo = [4, 5]
560        y = copy.copy(x)
561        self.assertEqual(list(x), list(y))
562        self.assertEqual(x.foo, y.foo)
563        self.assertTrue(x[0] is y[0])
564        self.assertTrue(x.foo is y.foo)
565
566    def test_deepcopy_list_subclass(self):
567        class C(list):
568            pass
569        x = C([[1, 2], 3])
570        x.foo = [4, 5]
571        y = copy.deepcopy(x)
572        self.assertEqual(list(x), list(y))
573        self.assertEqual(x.foo, y.foo)
574        self.assertTrue(x[0] is not y[0])
575        self.assertTrue(x.foo is not y.foo)
576
577    def test_copy_tuple_subclass(self):
578        class C(tuple):
579            pass
580        x = C([1, 2, 3])
581        self.assertEqual(tuple(x), (1, 2, 3))
582        y = copy.copy(x)
583        self.assertEqual(tuple(y), (1, 2, 3))
584
585    def test_deepcopy_tuple_subclass(self):
586        class C(tuple):
587            pass
588        x = C([[1, 2], 3])
589        self.assertEqual(tuple(x), ([1, 2], 3))
590        y = copy.deepcopy(x)
591        self.assertEqual(tuple(y), ([1, 2], 3))
592        self.assertTrue(x is not y)
593        self.assertTrue(x[0] is not y[0])
594
595    def test_getstate_exc(self):
596        class EvilState(object):
597            def __getstate__(self):
598                raise ValueError("ain't got no stickin' state")
599        self.assertRaises(ValueError, copy.copy, EvilState())
600
601    def test_copy_function(self):
602        self.assertEqual(copy.copy(global_foo), global_foo)
603        def foo(x, y): return x+y
604        self.assertEqual(copy.copy(foo), foo)
605        bar = lambda: None
606        self.assertEqual(copy.copy(bar), bar)
607
608    def test_deepcopy_function(self):
609        self.assertEqual(copy.deepcopy(global_foo), global_foo)
610        def foo(x, y): return x+y
611        self.assertEqual(copy.deepcopy(foo), foo)
612        bar = lambda: None
613        self.assertEqual(copy.deepcopy(bar), bar)
614
615    def _check_weakref(self, _copy):
616        class C(object):
617            pass
618        obj = C()
619        x = weakref.ref(obj)
620        y = _copy(x)
621        self.assertTrue(y is x)
622        del obj
623        y = _copy(x)
624        self.assertTrue(y is x)
625
626    def test_copy_weakref(self):
627        self._check_weakref(copy.copy)
628
629    def test_deepcopy_weakref(self):
630        self._check_weakref(copy.deepcopy)
631
632    def _check_copy_weakdict(self, _dicttype):
633        class C(object):
634            pass
635        a, b, c, d = [C() for i in range(4)]
636        u = _dicttype()
637        u[a] = b
638        u[c] = d
639        v = copy.copy(u)
640        self.assertFalse(v is u)
641        self.assertEqual(v, u)
642        self.assertEqual(v[a], b)
643        self.assertEqual(v[c], d)
644        self.assertEqual(len(v), 2)
645        del c, d
646        self.assertEqual(len(v), 1)
647        x, y = C(), C()
648        # The underlying containers are decoupled
649        v[x] = y
650        self.assertNotIn(x, u)
651
652    def test_copy_weakkeydict(self):
653        self._check_copy_weakdict(weakref.WeakKeyDictionary)
654
655    def test_copy_weakvaluedict(self):
656        self._check_copy_weakdict(weakref.WeakValueDictionary)
657
658    def test_deepcopy_weakkeydict(self):
659        class C(object):
660            def __init__(self, i):
661                self.i = i
662        a, b, c, d = [C(i) for i in range(4)]
663        u = weakref.WeakKeyDictionary()
664        u[a] = b
665        u[c] = d
666        # Keys aren't copied, values are
667        v = copy.deepcopy(u)
668        self.assertNotEqual(v, u)
669        self.assertEqual(len(v), 2)
670        self.assertFalse(v[a] is b)
671        self.assertFalse(v[c] is d)
672        self.assertEqual(v[a].i, b.i)
673        self.assertEqual(v[c].i, d.i)
674        del c
675        self.assertEqual(len(v), 1)
676
677    def test_deepcopy_weakvaluedict(self):
678        class C(object):
679            def __init__(self, i):
680                self.i = i
681        a, b, c, d = [C(i) for i in range(4)]
682        u = weakref.WeakValueDictionary()
683        u[a] = b
684        u[c] = d
685        # Keys are copied, values aren't
686        v = copy.deepcopy(u)
687        self.assertNotEqual(v, u)
688        self.assertEqual(len(v), 2)
689        (x, y), (z, t) = sorted(v.items(), key=lambda pair: pair[0].i)
690        self.assertFalse(x is a)
691        self.assertEqual(x.i, a.i)
692        self.assertTrue(y is b)
693        self.assertFalse(z is c)
694        self.assertEqual(z.i, c.i)
695        self.assertTrue(t is d)
696        del x, y, z, t
697        del d
698        self.assertEqual(len(v), 1)
699
700    def test_deepcopy_bound_method(self):
701        class Foo(object):
702            def m(self):
703                pass
704        f = Foo()
705        f.b = f.m
706        g = copy.deepcopy(f)
707        self.assertEqual(g.m, g.b)
708        self.assertTrue(g.b.__self__ is g)
709        g.b()
710
711
712def global_foo(x, y): return x+y
713
714def test_main():
715    support.run_unittest(TestCopy)
716
717if __name__ == "__main__":
718    test_main()
719