1"""Unit tests for the copy module."""
2
3import copy
4import copy_reg
5import weakref
6
7import unittest
8from test import test_support
9
10class TestCopy(unittest.TestCase):
11
12    # Attempt full line coverage of copy.py from top to bottom
13
14    def test_exceptions(self):
15        self.assertTrue(copy.Error is copy.error)
16        self.assertTrue(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.assertTrue(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.assertTrue(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.assertTrue(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.assertTrue(y is not x)
184        self.assertTrue(y[0] is not x[0])
185        self.assertTrue(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.assertTrue(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.assertTrue(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.assertTrue(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.assertTrue(x is not y)
269        self.assertTrue(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.assertTrue(y is not x)
277        self.assertTrue(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.assertTrue(x is not y)
285        self.assertTrue(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.assertTrue(y is not x)
293        self.assertTrue(y[0] is not x[0])
294        self.assertTrue(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.assertTrue(x is not y)
301        self.assertTrue(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.assertTrue(y is not x)
309        self.assertTrue(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.assertTrue(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.assertTrue(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.assertTrue(y is not x)
341        self.assertTrue(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.assertTrue(y is not x)
355        self.assertTrue(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.assertTrue(y is not x)
369        self.assertTrue(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.assertTrue(y is not x)
383        self.assertTrue(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.assertTrue(y is not x)
399        self.assertTrue(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.assertTrue(y is not x)
408        self.assertTrue(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.assertTrue(y is x)
419        y = copy.deepcopy(x)
420        self.assertTrue(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.assertTrue(y.__class__ is x.__class__)
430        y = copy.deepcopy(x)
431        self.assertTrue(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            __hash__ = None # Silence Py3k warning
440        x = C()
441        x.foo = [42]
442        y = copy.copy(x)
443        self.assertEqual(y, x)
444        y = copy.deepcopy(x)
445        self.assertEqual(y, x)
446        self.assertTrue(y.foo is not x.foo)
447
448    def test_reconstruct_state_setstate(self):
449        class C(object):
450            def __reduce__(self):
451                return (C, (), self.__dict__)
452            def __setstate__(self, state):
453                self.__dict__.update(state)
454            def __cmp__(self, other):
455                return cmp(self.__dict__, other.__dict__)
456            __hash__ = None # Silence Py3k warning
457        x = C()
458        x.foo = [42]
459        y = copy.copy(x)
460        self.assertEqual(y, x)
461        y = copy.deepcopy(x)
462        self.assertEqual(y, x)
463        self.assertTrue(y.foo is not x.foo)
464
465    def test_reconstruct_reflexive(self):
466        class C(object):
467            pass
468        x = C()
469        x.foo = x
470        y = copy.deepcopy(x)
471        self.assertTrue(y is not x)
472        self.assertTrue(y.foo is y)
473
474    # Additions for Python 2.3 and pickle protocol 2
475
476    def test_reduce_4tuple(self):
477        class C(list):
478            def __reduce__(self):
479                return (C, (), self.__dict__, iter(self))
480            def __cmp__(self, other):
481                return (cmp(list(self), list(other)) or
482                        cmp(self.__dict__, other.__dict__))
483            __hash__ = None # Silence Py3k warning
484        x = C([[1, 2], 3])
485        y = copy.copy(x)
486        self.assertEqual(x, y)
487        self.assertTrue(x is not y)
488        self.assertTrue(x[0] is y[0])
489        y = copy.deepcopy(x)
490        self.assertEqual(x, y)
491        self.assertTrue(x is not y)
492        self.assertTrue(x[0] is not y[0])
493
494    def test_reduce_5tuple(self):
495        class C(dict):
496            def __reduce__(self):
497                return (C, (), self.__dict__, None, self.iteritems())
498            def __cmp__(self, other):
499                return (cmp(dict(self), list(dict)) or
500                        cmp(self.__dict__, other.__dict__))
501            __hash__ = None # Silence Py3k warning
502        x = C([("foo", [1, 2]), ("bar", 3)])
503        y = copy.copy(x)
504        self.assertEqual(x, y)
505        self.assertTrue(x is not y)
506        self.assertTrue(x["foo"] is y["foo"])
507        y = copy.deepcopy(x)
508        self.assertEqual(x, y)
509        self.assertTrue(x is not y)
510        self.assertTrue(x["foo"] is not y["foo"])
511
512    def test_copy_slots(self):
513        class C(object):
514            __slots__ = ["foo"]
515        x = C()
516        x.foo = [42]
517        y = copy.copy(x)
518        self.assertTrue(x.foo is y.foo)
519
520    def test_deepcopy_slots(self):
521        class C(object):
522            __slots__ = ["foo"]
523        x = C()
524        x.foo = [42]
525        y = copy.deepcopy(x)
526        self.assertEqual(x.foo, y.foo)
527        self.assertTrue(x.foo is not y.foo)
528
529    def test_deepcopy_dict_subclass(self):
530        class C(dict):
531            def __init__(self, d=None):
532                if not d:
533                    d = {}
534                self._keys = list(d.keys())
535                dict.__init__(self, d)
536            def __setitem__(self, key, item):
537                dict.__setitem__(self, key, item)
538                if key not in self._keys:
539                    self._keys.append(key)
540        x = C(d={'foo':0})
541        y = copy.deepcopy(x)
542        self.assertEqual(x, y)
543        self.assertEqual(x._keys, y._keys)
544        self.assertTrue(x is not y)
545        x['bar'] = 1
546        self.assertNotEqual(x, y)
547        self.assertNotEqual(x._keys, y._keys)
548
549    def test_copy_list_subclass(self):
550        class C(list):
551            pass
552        x = C([[1, 2], 3])
553        x.foo = [4, 5]
554        y = copy.copy(x)
555        self.assertEqual(list(x), list(y))
556        self.assertEqual(x.foo, y.foo)
557        self.assertTrue(x[0] is y[0])
558        self.assertTrue(x.foo is y.foo)
559
560    def test_deepcopy_list_subclass(self):
561        class C(list):
562            pass
563        x = C([[1, 2], 3])
564        x.foo = [4, 5]
565        y = copy.deepcopy(x)
566        self.assertEqual(list(x), list(y))
567        self.assertEqual(x.foo, y.foo)
568        self.assertTrue(x[0] is not y[0])
569        self.assertTrue(x.foo is not y.foo)
570
571    def test_copy_tuple_subclass(self):
572        class C(tuple):
573            pass
574        x = C([1, 2, 3])
575        self.assertEqual(tuple(x), (1, 2, 3))
576        y = copy.copy(x)
577        self.assertEqual(tuple(y), (1, 2, 3))
578
579    def test_deepcopy_tuple_subclass(self):
580        class C(tuple):
581            pass
582        x = C([[1, 2], 3])
583        self.assertEqual(tuple(x), ([1, 2], 3))
584        y = copy.deepcopy(x)
585        self.assertEqual(tuple(y), ([1, 2], 3))
586        self.assertTrue(x is not y)
587        self.assertTrue(x[0] is not y[0])
588
589    def test_getstate_exc(self):
590        class EvilState(object):
591            def __getstate__(self):
592                raise ValueError, "ain't got no stickin' state"
593        self.assertRaises(ValueError, copy.copy, EvilState())
594
595    def test_copy_function(self):
596        self.assertEqual(copy.copy(global_foo), global_foo)
597        def foo(x, y): return x+y
598        self.assertEqual(copy.copy(foo), foo)
599        bar = lambda: None
600        self.assertEqual(copy.copy(bar), bar)
601
602    def test_deepcopy_function(self):
603        self.assertEqual(copy.deepcopy(global_foo), global_foo)
604        def foo(x, y): return x+y
605        self.assertEqual(copy.deepcopy(foo), foo)
606        bar = lambda: None
607        self.assertEqual(copy.deepcopy(bar), bar)
608
609    def _check_weakref(self, _copy):
610        class C(object):
611            pass
612        obj = C()
613        x = weakref.ref(obj)
614        y = _copy(x)
615        self.assertTrue(y is x)
616        del obj
617        y = _copy(x)
618        self.assertTrue(y is x)
619
620    def test_copy_weakref(self):
621        self._check_weakref(copy.copy)
622
623    def test_deepcopy_weakref(self):
624        self._check_weakref(copy.deepcopy)
625
626    def _check_copy_weakdict(self, _dicttype):
627        class C(object):
628            pass
629        a, b, c, d = [C() for i in xrange(4)]
630        u = _dicttype()
631        u[a] = b
632        u[c] = d
633        v = copy.copy(u)
634        self.assertFalse(v is u)
635        self.assertEqual(v, u)
636        self.assertEqual(v[a], b)
637        self.assertEqual(v[c], d)
638        self.assertEqual(len(v), 2)
639        del c, d
640        self.assertEqual(len(v), 1)
641        x, y = C(), C()
642        # The underlying containers are decoupled
643        v[x] = y
644        self.assertNotIn(x, u)
645
646    def test_copy_weakkeydict(self):
647        self._check_copy_weakdict(weakref.WeakKeyDictionary)
648
649    def test_copy_weakvaluedict(self):
650        self._check_copy_weakdict(weakref.WeakValueDictionary)
651
652    def test_deepcopy_weakkeydict(self):
653        class C(object):
654            def __init__(self, i):
655                self.i = i
656        a, b, c, d = [C(i) for i in xrange(4)]
657        u = weakref.WeakKeyDictionary()
658        u[a] = b
659        u[c] = d
660        # Keys aren't copied, values are
661        v = copy.deepcopy(u)
662        self.assertNotEqual(v, u)
663        self.assertEqual(len(v), 2)
664        self.assertFalse(v[a] is b)
665        self.assertFalse(v[c] is d)
666        self.assertEqual(v[a].i, b.i)
667        self.assertEqual(v[c].i, d.i)
668        del c
669        self.assertEqual(len(v), 1)
670
671    def test_deepcopy_weakvaluedict(self):
672        class C(object):
673            def __init__(self, i):
674                self.i = i
675        a, b, c, d = [C(i) for i in xrange(4)]
676        u = weakref.WeakValueDictionary()
677        u[a] = b
678        u[c] = d
679        # Keys are copied, values aren't
680        v = copy.deepcopy(u)
681        self.assertNotEqual(v, u)
682        self.assertEqual(len(v), 2)
683        (x, y), (z, t) = sorted(v.items(), key=lambda pair: pair[0].i)
684        self.assertFalse(x is a)
685        self.assertEqual(x.i, a.i)
686        self.assertTrue(y is b)
687        self.assertFalse(z is c)
688        self.assertEqual(z.i, c.i)
689        self.assertTrue(t is d)
690        del x, y, z, t
691        del d
692        self.assertEqual(len(v), 1)
693
694    def test_deepcopy_bound_method(self):
695        class Foo(object):
696            def m(self):
697                pass
698        f = Foo()
699        f.b = f.m
700        g = copy.deepcopy(f)
701        self.assertEqual(g.m, g.b)
702        self.assertTrue(g.b.im_self is g)
703        g.b()
704
705
706def global_foo(x, y): return x+y
707
708def test_main():
709    test_support.run_unittest(TestCopy)
710
711if __name__ == "__main__":
712    test_main()
713