From 339f970cf43070b3a95ece4e6a39dd57a34eab97 Mon Sep 17 00:00:00 2001 From: Yuxin Wu Date: Fri, 10 Oct 2025 22:10:15 -0700 Subject: [PATCH] Avoid ref cycle among MagicMock and its magic methods --- Lib/test/test_unittest/testmock/testmock.py | 20 ++++++++++++++++++++ Lib/unittest/mock.py | 5 +++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_unittest/testmock/testmock.py b/Lib/test/test_unittest/testmock/testmock.py index 386d53bf5a5c63..039f8fa044d00c 100644 --- a/Lib/test/test_unittest/testmock/testmock.py +++ b/Lib/test/test_unittest/testmock/testmock.py @@ -2426,5 +2426,25 @@ async def method(self): for m in (mock.method, mock.class_method, mock.static_method): self.assertIsInstance(m, AsyncMock) + def test_mock_no_reference_cycle(self): + obj = Something() + ref = sys.getrefcount(obj) + mock = MagicMock() + mock.mocked_list = [obj] + del mock + ref2 = sys.getrefcount(obj) + self.assertEqual(ref, ref2) + + def test_mock_patch_no_reference_cycle(self): + class Foo(): + one = 'one' + + obj = Something() + ref = sys.getrefcount(obj) + with mock.patch.object(Foo, 'one', return_value=3): + Foo.one(obj) + ref2 = sys.getrefcount(obj) + self.assertEqual(ref, ref2) + if __name__ == '__main__': unittest.main() diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 0bb6750655380d..d1fdde9198ddf3 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -39,6 +39,7 @@ from unittest.util import safe_repr from functools import wraps, partial from threading import RLock +import weakref class InvalidSpecError(Exception): @@ -2195,7 +2196,7 @@ def _mock_set_magics(self): _type = type(self) for entry in these_magics: - setattr(_type, entry, MagicProxy(entry, self)) + setattr(_type, entry, MagicProxy(entry, weakref.ref(self))) @@ -2255,7 +2256,7 @@ def __init__(self, name, parent): def create_mock(self): entry = self.name - parent = self.parent + parent = self.parent() # self.parent is a weakref to the parent m = parent._get_child_mock(name=entry, _new_name=entry, _new_parent=parent) setattr(parent, entry, m)