Skip to content

Commit 9a4153f

Browse files
committed
gh-142254: rewrite test without relying on sys.getrefcount()
These now pass on 3.10-3.15 as well as PyPy 3.11.
1 parent 4c5b00c commit 9a4153f

1 file changed

Lines changed: 33 additions & 26 deletions

File tree

Lib/test/test_copy.py

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -435,38 +435,45 @@ def test_deepcopy_reflexive_dict(self):
435435
self.assertEqual(len(y), 1)
436436

437437
def test_deepcopy_keepalive(self):
438-
mutable = []
439-
def count_refs():
440-
return sys.getrefcount(mutable)
441-
class C:
438+
class Target:
439+
pass
440+
class Dropper:
441+
def __init__(self, to_clear):
442+
self.to_clear = to_clear
442443
def __deepcopy__(self, memo):
443-
self.recorded = count_refs()
444+
self.to_clear.clear()
444445
return self
445-
x = [mutable, 42, observer := C()]
446-
y = copy.deepcopy(x)
446+
class Checker:
447+
def __init__(self, ref):
448+
self.ref = ref
449+
self.was_alive = None
450+
def __deepcopy__(self, memo):
451+
support.gc_collect() # For PyPy or other GCs.
452+
self.was_alive = self.ref() is not None
453+
return self
454+
weak_ref = weakref.ref(target := Target())
455+
holder = [target]
456+
del target # holder[0] is now only strong ref
457+
container = [holder, Dropper(holder), *((1,) * 1000), (checker := Checker(weak_ref))]
458+
copy.deepcopy(container)
459+
self.assertTrue(checker.was_alive)
447460
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)
461+
self.assertIsNone(weak_ref())
451462

452463
def test_deepcopy_dont_memo_immutable(self):
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())}")
464+
class ByRef:
465+
def __init__(self):
466+
self.copied = 0
467+
def __deepcopy__(self, memo):
468+
self.copied += 1
469+
return self
470+
y = copy.deepcopy(x := [br := ByRef(), br])
471+
self.assertEqual(br.copied, 2)
472+
self.assertEqual(y, x)
467473
# Tuples with immutable contents are immutable for deepcopy.
468-
with self.subTest(kind="tuple_with_string"):
469-
run_case((f"mortal_immutable_{id(object())}",))
474+
y = copy.deepcopy(x := [(br := ByRef()), (br,)])
475+
self.assertEqual(br.copied, 2)
476+
self.assertEqual(y, x)
470477

471478
def test_deepcopy_inst_vanilla(self):
472479
class C:

0 commit comments

Comments
 (0)