classification
Title: MagicMock().__iter__.return_value is different from MagicMock().__iter__()
Type: Stage: resolved
Components: Library (Lib) Versions: Python 3.6, Python 3.4, Python 3.5, Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: mariocj89, michael.foord, mrh1997, xtreak
Priority: normal Keywords:

Created on 2018-04-06 11:50 by mrh1997, last changed 2018-10-27 15:41 by michael.foord. This issue is now closed.

Messages (5)
msg315016 - (view) Author: Robert (mrh1997) * Date: 2018-04-06 11:50
According to the documentation .return_value should be identical to the object returned when calling the mock ("assert m() is m.return_value")

This is the case except on objects returned by __iter__ on MagicMocks. The following script demonstrates the problem:
----
from unittest.mock import MagicMock
m = MagicMock()
assert x.__iter__() is x.__iter__.return_value    # <- fails
----

In fact __iter__() returns the object "iter([])" (which matches the documentation) while __iter__.return_value return a MagicMock object (which does not match the documentation).

When replacing "__iter__" with any other special function MagicMock works as expected.
msg325863 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2018-09-20 12:37
Can you please link to the relevant documentation that is misleading? As I can see from the source code return value is a Mock object [1] which I believe the docs state as below : 

https://docs.python.org/3/library/unittest.mock.html#calling

> Mock objects are callable. The call will return the value set as the return_value attribute. The default return value is a new Mock object; it is created the first time the return value is accessed (either explicitly or by calling the Mock) - but it is stored and the same one returned each time.

from unittest.mock import MagicMock
x = MagicMock()

print(x.__iter__())
print(x.__iter__.return_value)
print(x.return_value)


➜  cpython git:(master) ./python.exe bpo33236.py
<list_iterator object at 0x10d0797f0>
<MagicMock name='mock.__iter__()' id='4513568752'>
<MagicMock name='mock()' id='4513642816'>


[1] : https://github.com/python/cpython/blob/b10a64d117de6121ea3e79c467c4107f8f399f3d/Lib/unittest/mock.py#L463


Thanks
msg325927 - (view) Author: Robert (mrh1997) * Date: 2018-09-20 20:31
According to this chapter ( https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock ) the specialmethods in MagicMock are different:

.return_value is preinitialized with defaultvalues, which depends on the operator. In the case of .__iter__ this is "iter([])".
This is the case when running __iter__(), but not when running __iter__.result_value
msg328649 - (view) Author: Mario Corchero (mariocj89) * (Python triager) Date: 2018-10-27 13:52
iter is initialized by using side_effects, not return_value.

The statement "According to the documentation .return_value should be identical to the object returned when calling the mock" works only when it return_value has been used to define the behaviour of the mock.

Example:

```
>>> m = MagicMock(side_effect=lambda: 1)
>>> m()
1
>>> m.return_value
<MagicMock name='mock()' id='140107830678472'>
>>> m() is m.return_value
False
```
msg328652 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2018-10-27 15:41
This isn't a bug. This is the intended behaviour, otherwise MagicMock objects would error out on iteration.
History
Date User Action Args
2018-10-27 15:41:28michael.foordsetstatus: open -> closed
resolution: not a bug
messages: + msg328652

stage: resolved
2018-10-27 13:52:14mariocj89setnosy: + mariocj89
messages: + msg328649
2018-09-20 20:31:02mrh1997setmessages: + msg325927
2018-09-20 12:37:21xtreaksetnosy: + xtreak
messages: + msg325863
2018-04-08 18:27:41ned.deilysetnosy: + michael.foord
2018-04-06 11:50:07mrh1997create