8000 [3.12] gh-123934: Fix `MagicMock` not to reset magic method return va… · python/cpython@e9578f6 · GitHub
[go: up one dir, main page]

Skip to content

Commit e9578f6

Browse files
[3.12] gh-123934: Fix MagicMock not to reset magic method return values (GH-124038) (#124232)
gh-123934: Fix `MagicMock` not to reset magic method return values (GH-124038) (cherry picked from commit 7628f67) Co-authored-by: sobolevn <mail@sobolevn.me>
1 parent a82a2f1 commit e9578f6

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

Lib/test/test_unittest/testmock/testmagicmethods.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,45 @@ def test_magic_methods_fspath(self):
331331
self.assertEqual(os.fspath(mock), expected_path)
332332
mock.__fspath__.assert_called_once()
333333

334+
def test_magic_mock_does_not_reset_magic_returns(self):
335+
# https://github.com/python/cpython/issues/123934
336+
for reset in (True, False):
337+
with self.subTest(reset=reset):
338+
mm = MagicMock()
339+
self.assertIs(type(mm.__str__()), str)
340+
mm.__str__.assert_called_once()
341+
342+
self.assertIs(type(mm.__hash__()), int)
343+
mm.__hash__.assert_called_once()
344+
345+
for _ in range(3):
346+
# Repeat reset several times to be sure:
347+
mm.reset_mock(return_value=reset)
348+
349+
self.assertIs(type(mm.__str__()), str)
350+
mm.__str__.assert_called_once()
351+
352+
self.assertIs(type(mm.__hash__()), int)
353+
mm.__hash__.assert_called_once()
354+
355+
def test_magic_mock_resets_manual_mocks(self):
356+
mm = MagicMock()
357+
mm.__iter__ = MagicMock(return_value=iter([1]))
358+
mm.custom = MagicMock(return_value=2)
359+
self.assertEqual(list(iter(mm)), [1])
360+
self.assertEqual(mm.custom(), 2)
361+
362+
mm.reset_mock(return_value=True)
363+
self.assertEqual(list(iter(mm)), [])
364+
self.assertIsInstance(mm.custom(), MagicMock)
365+
366+
def test_magic_mock_resets_manual_mocks_empty_iter(self):
367+
mm = MagicMock()
368+
mm.__iter__.return_value = []
369+
self.assertEqual(list(iter(mm)), [])
370+
371+
mm.reset_mock(return_value=True)
372+
self.assertEqual(list(iter(mm)), [])
334373

335374
def test_magic_methods_and_spec(self):
336375
class Iterable(object):

Lib/unittest/mock.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ def __set_side_effect(self, value):
598598
side_effect = property(__get_side_effect, __set_side_effect)
599599

600600

601-
def reset_mock(self, visited=None,*, return_value=False, side_effect=False):
601+
def reset_mock(self, visited=None, *, return_value=False, side_effect=False):
602602
"Restore the mock object to its initial state."
603603
if visited is None:
604604
visited = []
@@ -2189,6 +2189,17 @@ def mock_add_spec(self, spec, spec_set=False):
21892189
self._mock_add_spec(spec, spec_set)
21902190
self._mock_set_magics()
21912191

2192+
def reset_mock(self, /, *args, return_value=False, **kwargs):
2193+
if (
2194+
return_value
2195+
and self._mock_name
2196+
and _is_magic(self._mock_name)
2197+
):
2198+
# Don't reset return values for magic methods,
2199+
# otherwise `m.__str__` will start
2200+
# to return `MagicMock` instances, instead of `str` instances.
2201+
return_value = False
2202+
super().reset_mock(*args, return_value=return_value, **kwargs)
21922203

21932204

21942205
class MagicProxy(Base):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :class:`unittest.mock.MagicMock` reseting magic methods return values
2+
after ``.reset_mock(return_value=True)`` was called.

0 commit comments

Comments
 (0)
0