Title: unitest.mock: Using autospec=True conflicts with 'wraps'
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.7, Python 3.6
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: John Villalovos, Lukas Anzinger, ezio.melotti, michael.foord, rbcollins, xtreak
Priority: normal Keywords: patch

Created on 2017-10-18 00:48 by John Villalovos, last changed 2019-12-02 08:29 by xtreak.

File name Uploaded Description Edit
0001-bpo-31807-unittest.mock-Fix-common-use-of-autospec-T.patch Lukas Anzinger, 2017-11-15 15:29
Messages (3)
msg304549 - (view) Author: John Villalovos (John Villalovos) Date: 2017-10-18 00:48
If have autospec=True, then no ValueError is raised. If autospec=False or not defined, then the ValueError is raised.

import sys
from unittest import mock

def wrapped_func(value):
    raise ValueError(value)

@mock.patch('__main__.wrapped_func', autospec=True, wraps=wrapped_func)
def main(mock_wrap):


if '__main__' == __name__:
msg306273 - (view) Author: Lukas Anzinger (Lukas Anzinger) * Date: 2017-11-15 15:29
I can reproduce the problem and have analyzed it a bit. My use case is a bit different, I want to use autospec=True and wraps= so that I can mock unbound methods but return the result from the original method (see also

The problem in the mock code is that mock.return_value actually calls __get_return_value() which replaces the actual return value mock.DEFAULT (which is stored in self._mock_return_value) with a new child mock. When the mock is then called and _mock_call() is executed, the wrapped function is not executed because self._mock_return_value is not mock.DEFAULT anymore:

    if (self._mock_wraps is not None and
         self._mock_return_value is DEFAULT):
        return self._mock_wraps(*args, **kwargs)
    if ret_val is DEFAULT:
        ret_val = self.return_value
    return ret_val

Since self._mock_return_value is not DEFAULT anymore it doesn't matter if the mock wraps something and it will instead just return a new mock.

I think that the side effect of the assignment to self.return_value in _setup_func() is not intentional, i.e. the child mock should actually be created only if there is an outside access to return_value, but not when it is just wrapped in a function. The assignment can be made side effect free by assigning the internal attribute _mock_return_value (see attached patch). This solves the problem for me.
I've attached a patch that fixes the problem and doesn't seem to introduce a regression (all unittest.mock tests pass).

If somebody is interested in getting this merged, I'm happy to provide a regression test and everything else that is needed to get this merged.


msg352287 - (view) Author: Lukas Anzinger (Lukas Anzinger) * Date: 2019-09-13 11:00

I just wanted to ask what the status for this bug is.

I'm still interested in getting this merged and would be happy to help.

Date User Action Args
2019-12-02 08:29:10xtreaksetnosy: + xtreak
2019-09-13 11:00:15Lukas Anzingersetmessages: + msg352287
2017-11-15 15:29:37Lukas Anzingersetfiles: + 0001-bpo-31807-unittest.mock-Fix-common-use-of-autospec-T.patch
versions: + Python 3.7
nosy: + Lukas Anzinger

messages: + msg306273

keywords: + patch
2017-10-20 18:50:30terry.reedysetnosy: + rbcollins, ezio.melotti
2017-10-20 18:50:09terry.reedysetnosy: + michael.foord
2017-10-18 05:07:19John Villalovossettitle: Using autospec=True conflicts with 'wraps' -> unitest.mock: Using autospec=True conflicts with 'wraps'
2017-10-18 00:48:15John Villalovoscreate