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
reset_mock on mock created by mock_open causes infinite recursion #62822
Comments
As reported at: http://code.google.com/p/mock/issues/detail?id=209 >>> from unittest import mock
[107971 refs]
>>> mock.mock_open
<function mock_open at 0x10cff9d20>
[107974 refs]
>>> a = mock.mock_open()
[109965 refs]
>>> a.reset_mock()
... |
The best way to solve this seems to be to track a set of visited ids (mocks we've reset) and not recurse into mocks we've already done. This is similar to the patch proposed on the google code issue - but not identical as that uses a list and has it as the default argument to reset_mock. |
Hi all, I've fixed the infinite recursion in >>> from unittest import mock
>>> a = mock.mock_open()
>>> a.reset_mock()
>>> a
<MagicMock name='open' spec='builtin_function_or_method' id='4449688192'> |
The proposed patch does solve the infinite recursion bug, but a different problem appears when resetting the same mock multiple times: it only works the first time. Using the patch as it stands: >>> from unittest.mock import mock_open
>>> mo = mock_open()
>>> a = mo()
>>> mo.call_count
1
>>> mo.reset_mock()
>>> mo.call_count
0
>>> b = mo()
>>> mo.call_count
1
>>> mo.reset_mock()
>>> mo.call_count
1 And here from a version with an added print(visited) statement: >>> from unittest.mock import mock_open
>>> mo = mock_open()
>>> a = mo()
>>> mo.call_count
1
>>> mo.reset_mock()
[]
[139803191795152]
[139803191795152, 139803181189008]
[139803191795152, 139803181189008, 139803213598416]
[139803191795152, 139803181189008, 139803213598416, 139803213652048]
[139803191795152, 139803181189008, 139803213598416, 139803213652048]
>>> mo.call_count
0
>>> b = mo()
>>> mo.call_count
1
>>> mo.reset_mock()
[139803191795152, 139803181189008, 139803213598416, 139803213652048, 139803213598288]
>>> mo.call_count
1
>>> mo.reset_mock(visited=[])
[]
[139803191795152]
[139803191795152, 139803181189008]
[139803191795152, 139803181189008, 139803213598416]
[139803191795152, 139803181189008, 139803213598416, 139803213652048]
[139803191795152, 139803181189008, 139803213598416, 139803213652048]
>>> mo.call_count
0 As you can see, for some reason I don't quite grasp, the 'visited' parameter persists across calls to reset_mock(), meaning that the very first call does indeed reset it but subsequent calls do not. As the last two calls show, one can force a reset by explicitly providing an empty list, but this is starting to become a change in API and not just a bugfix... |
Sorry Michael, I should have read your second comment more closely since you already pointed out that using a list as default argument is bad. It is, however, easily fixed by changing to this: def reset_mock(self, visited=None):
"Restore the mock object to its initial state."
if visited is None:
visited = []
if id(self) in visited:
return |
I should have read more carefully, too! Thanks to both. |
And here's an actual patch with the corrected code |
I've been bitten by this issue with a custom psycopg2 mock. >>> cur = mock.Mock()
>>>
>>> cur.connection.cursor.return_value = cur
>>> cur.reset_mock()
RuntimeError: maximum recursion depth exceeded the patch looks ok, except the mix of tab and spaces :-) |
Applying this to 3.4 and up with a test. Laurent, it would be good to sign the CLA - since your change here is minimal and Nicola has, I'm just going ahead. |
New changeset 4c8cb603ab42 by Robert Collins in branch '3.4':
|
New changeset c0ec61cf5a7d by Robert Collins in branch '3.5':
New changeset a4fe32477df6 by Robert Collins in branch 'default':
|
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: