|
1 | 1 | """Unit tests for the copy module.""" |
| 2 | +import sys |
2 | 3 |
|
3 | 4 | import copy |
4 | 5 | import copyreg |
@@ -434,25 +435,38 @@ def test_deepcopy_reflexive_dict(self): |
434 | 435 | self.assertEqual(len(y), 1) |
435 | 436 |
|
436 | 437 | def test_deepcopy_keepalive(self): |
437 | | - memo = {} |
438 | | - x = [] |
439 | | - y = copy.deepcopy(x, memo) |
440 | | - self.assertIs(memo[id(memo)][0], x) |
| 438 | + mutable = [] |
| 439 | + def count_refs(): |
| 440 | + return sys.getrefcount(mutable) |
| 441 | + class C: |
| 442 | + def __deepcopy__(self, memo): |
| 443 | + self.recorded = count_refs() |
| 444 | + return self |
| 445 | + x = [mutable, 42, observer := C()] |
| 446 | + y = copy.deepcopy(x) |
| 447 | + support.gc_collect() # For PyPy or other GCs. |
| 448 | + # Additional keepalive ref dropped after copy: |
| 449 | + self.assertGreater(observer.recorded, count_refs()) |
| 450 | + self.assertEqual(observer.recorded - count_refs(), 1) |
441 | 451 |
|
442 | 452 | def test_deepcopy_dont_memo_immutable(self): |
443 | | - memo = {} |
444 | | - x = [1, 2, 3, 4] |
445 | | - y = copy.deepcopy(x, memo) |
446 | | - self.assertEqual(y, x) |
447 | | - # There's the entry for the new list, and the keep alive. |
448 | | - self.assertEqual(len(memo), 2) |
449 | | - |
450 | | - memo = {} |
451 | | - x = [(1, 2)] |
452 | | - y = copy.deepcopy(x, memo) |
453 | | - self.assertEqual(y, x) |
| 453 | + def run_case(immutable): |
| 454 | + def count_refs(): |
| 455 | + return sys.getrefcount(immutable) |
| 456 | + class C: |
| 457 | + def __deepcopy__(self, memo): |
| 458 | + self.recorded = count_refs() |
| 459 | + return self |
| 460 | + x = [immutable, 42, observer := C()] |
| 461 | + y = copy.deepcopy(x) |
| 462 | + support.gc_collect() # For PyPy or other GCs |
| 463 | + self.assertIs(y[0], x[0]) |
| 464 | + self.assertEqual(count_refs(), observer.recorded) |
| 465 | + with self.subTest(kind="string"): |
| 466 | + run_case(f"mortal_immutable_{id(object())}") |
454 | 467 | # Tuples with immutable contents are immutable for deepcopy. |
455 | | - self.assertEqual(len(memo), 2) |
| 468 | + with self.subTest(kind="tuple_with_string"): |
| 469 | + run_case((f"mortal_immutable_{id(object())}",)) |
456 | 470 |
|
457 | 471 | def test_deepcopy_inst_vanilla(self): |
458 | 472 | class C: |
|
0 commit comments