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