test_copy.py revision 3add4d78ff9f5de02e2c0de09efe9a9b5317539f
1"""Unit tests for the copy module."""
2
3import sys
4import copy
5import copy_reg
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.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, 2**100, 3.14, True, False, 1j,
86                 "hello", "hello\u1234", f.__code__,
87                 NewStyle, range(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 __eq__(self, other):
108                return 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 __eq__(self, other):
119                return 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 __eq__(self, other):
130                return 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 __eq__(self, other):
141                return 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 __eq__(self, other):
152                return 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 __eq__(self, other):
165                return 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(metaclass=Meta):
195            pass
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, 2**100, 3.14, True, False, 1j,
259                 "hello", "hello\u1234", f.__code__,
260                 NewStyle, range(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(TypeError, 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 __eq__(self, other):
323                return 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 __eq__(self, other):
336                return 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 __eq__(self, other):
350                return 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 __eq__(self, other):
364                return 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 __eq__(self, other):
378                return 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 __eq__(self, other):
394                return 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 __eq__(self, other):
438                return 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 __eq__(self, other):
454                return 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 __eq__(self, other):
479                return (list(self) == list(other) and
480                        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.items())
495            def __eq__(self, other):
496                return (dict(self) == dict(other) and
497                        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
585def global_foo(x, y): return x+y
586
587def test_main():
588    test_support.run_unittest(TestCopy)
589
590if __name__ == "__main__":
591    test_main()
592