-
-
Notifications
You must be signed in to change notification settings - Fork 30.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-123934: Fix MagicMock
not to reset magic method return values
#124038
Conversation
I consider this a bug fix, so I propose to backport this to 3.12 and 3.13 |
|
||
def test_magic_mock_resets_manual_mocks(self): | ||
mm = MagicMock() | ||
mm.__iter__ = MagicMock(return_value=iter([1])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, okay, things I didn't know about MagicMock and I'm not sure I like ;-) :
>>> m = MagicMock()
>>> list(iter(m))
[]
However, what happens if you change the above line to:
mm.__iter__ = MagicMock(return_value=iter([1])) | |
mm.__iter__ = MagicMock(return_value=[]) |
I'm not sure it makes any difference, but mainly 'cos of the weird behaviour I started with an example of ;-)
Here's some playing around in a Python 3.12 interpreter that might give more of a feel for what I'm trying to communicate:
>>> from unittest.mock import MagicMock
>>> m = MagicMock()
>>> m.__iter__
<MagicMock name='mock.__iter__' id='4307758752'>
>>> m.__iter__.return_value = []
>>> iter(m)
<list_iterator object at 0x10088f8b0>
>>> list(iter(m))
[]
>>> list(iter(m)) is m.__iter__.return_value
False
>>> m.__iter__.return_value = [1, 2, 3]
>>> list(iter(m))
[1, 2, 3]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added one more test with the behavior you are showing here. I executed these two tests
def test_magic_mock_resets_manual_mocks(self):
mm = MagicMock()
mm.__iter__ = MagicMock(return_value=iter([1]))
mm.custom = MagicMock(return_value=2)
self.assertEqual(list(iter(mm)), [1])
self.assertEqual(mm.custom(), 2)
mm.reset_mock(return_value=True)
self.assertEqual(list(iter(mm)), [])
self.assertIsInstance(mm.custom(), MagicMock)
def test_magic_mock_resets_manual_mocks_empty_iter(self):
mm = MagicMock()
mm.__iter__.return_value = []
self.assertEqual(list(iter(mm)), [])
mm.reset_mock(return_value=True)
self.assertEqual(list(iter(mm)), [])
on main
(with no changes from this PR) and it was also successful.
Should I cover anything else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I think this is where I got confused; the docs aren't great here. I believe the intention may be that return_value
is only a boolean, or it may be that it's intended as a way to provide a new value.
If you feel inclined, it'd be good to clarify the docs on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said inline, the docs aren't great. Any reason not to just add a type annotation of : bool
to that parameter?
Anyway, I think this is good to land, thanks for the attention to detail here!
|
||
def test_magic_mock_resets_manual_mocks(self): | ||
mm = MagicMock() | ||
mm.__iter__ = MagicMock(return_value=iter([1])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I think this is where I got confused; the docs aren't great here. I believe the intention may be that return_value
is only a boolean, or it may be that it's intended as a way to provide a new value.
If you feel inclined, it'd be good to clarify the docs on this.
Thanks @sobolevn for the PR 🌮🎉.. I'm working now to backport this PR to: 3.12, 3.13. |
…ues (pythonGH-124038) (cherry picked from commit 7628f67) Co-authored-by: sobolevn <mail@sobolevn.me>
Thanks a lot for the helpful reviews! I would prefer to work on docs in a separate PR, because it is unrelated to this problem. Working on it now! 👍 |
…ues (pythonGH-124038) (cherry picked from commit 7628f67) Co-authored-by: sobolevn <mail@sobolevn.me>
GH-124231 is a backport of this pull request to the 3.13 branch. |
GH-124232 is a backport of this pull request to the 3.12 branch. |
Refs https://github.com/python/cpython/pull/17409/files
reset_mock
resetsMagicMock
's magic methods in an unexpected way #123934