classification
Title: Setting a exception side_effect on a mock from create_autospec does not work
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.6, Python 3.4, Python 3.5
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: Ignacio Rossi, and, berker.peksag, michael.foord, python-dev, rbcollins
Priority: normal Keywords: patch

Created on 2015-03-14 00:45 by Ignacio Rossi, last changed 2015-11-18 11:13 by and. This issue is now closed.

Files
File name Uploaded Description Edit
autospec_exception.patch Ignacio Rossi, 2015-03-14 04:19 Test and fix for autospeccing functions with exceptions review
Messages (7)
msg238064 - (view) Author: Ignacio Rossi (Ignacio Rossi) * Date: 2015-03-14 00:45
The following fails on python 3.4.2, 3.4.3 and 3.5.0a2 (downloaded from python.org and compiled on Ubuntu 14.04). 
The same happens when using mock.patch with autospec=True.

>>> from unittest.mock import create_autospec
>>> def function():
...     pass
... 
>>> mock = create_autospec(function)
>>> mock.side_effect = ValueError('MyError')
>>> mock()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 3, in function
  File "/usr/local/lib/python3.5/unittest/mock.py", line 910, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/usr/local/lib/python3.5/unittest/mock.py", line 963, in _mock_call
    effect = self.side_effect
  File "/usr/local/lib/python3.5/unittest/mock.py", line 510, in __get_side_effect
    sf = _MockIter(sf)
  File "/usr/local/lib/python3.5/unittest/mock.py", line 351, in __init__
    self.obj = iter(obj)
TypeError: 'ValueError' object is not iterable

But, on Python 3.3.5, 3.4.0, or when the mock is created via Mock(), for  instance, the exception is raised as expected:

[...]
>>> mock()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 3, in function
  File "/usr/lib/python3.4/unittest/mock.py", line 885, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/usr/lib/python3.4/unittest/mock.py", line 941, in _mock_call
    raise effect
ValueError: MyError
msg238071 - (view) Author: Ignacio Rossi (Ignacio Rossi) * Date: 2015-03-14 04:19
The problem only affects autospecced functions.

Apparently, the problem lies here (all code excerpts from Lib/unittest/mock.py):

- When autospeccing functions, the Mock._mock_delegate field is populated at the end of _setup_func (and its the only place I found where the delegate is set):

197 def _setup_func(funcopy, mock):
[...]
237     mock._mock_delegate = funcopy

- Mock.side_effect is a property, and proxies the get/set to _mock_delegate when it exists, and on the way out does not detect the exception and tries to make an _IterMock out of it and everything explodes.

 504     def __get_side_effect(self):
 505         delegated = self._mock_delegate
 506         if delegated is None:
 507             return self._mock_side_effect
 508         sf = delegated.side_effect
 509         if sf is not None and not callable(sf) and not isinstance(sf, _MockIter):
 510             sf = _MockIter(sf)

I've attached a patch which adds a test for this use case, and a proposed fix. Hope it helps :)
msg246707 - (view) Author: Robert Collins (rbcollins) * (Python committer) Date: 2015-07-14 01:17
Also reported in the mock project as https://github.com/testing-cabal/mock/issues/264
msg246708 - (view) Author: Robert Collins (rbcollins) * (Python committer) Date: 2015-07-14 01:19
This looks fine to me, I'm going to apply it.
msg246709 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2015-07-14 01:59
New changeset db825807ab04 by Robert Collins in branch 'default':
Issue #23661: unittest.mock side_effects can now be exceptions again.
https://hg.python.org/cpython/rev/db825807ab04
msg246716 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2015-07-14 04:48
New changeset 7021d46c490e by Robert Collins in branch '3.5':
Issue #23661: unittest.mock side_effects can now be exceptions again.
https://hg.python.org/cpython/rev/7021d46c490e

New changeset 231bf0840f8f by Robert Collins in branch 'default':
Issue 23661: null-merge with 3.5.
https://hg.python.org/cpython/rev/231bf0840f8f
msg254842 - (view) Author: Dmitry Andreychuk (and) Date: 2015-11-18 11:13
python 3.4.3 is also affected. Is it possible to fix this in branch 3.4?
History
Date User Action Args
2015-11-18 11:13:20andsetnosy: + and

messages: + msg254842
versions: + Python 3.4
2015-07-16 01:55:59berker.peksagsetstatus: open -> closed
stage: resolved
resolution: fixed
versions: + Python 3.6, - Python 3.4
2015-07-14 04:48:41python-devsetmessages: + msg246716
2015-07-14 01:59:09python-devsetnosy: + python-dev
messages: + msg246709
2015-07-14 01:19:20rbcollinssetmessages: + msg246708
2015-07-14 01:17:53rbcollinssetnosy: + rbcollins
messages: + msg246707
2015-03-14 22:32:58ned.deilysetnosy: + michael.foord, berker.peksag
2015-03-14 04:19:33Ignacio Rossisetfiles: + autospec_exception.patch
keywords: + patch
messages: + msg238071
2015-03-14 00:45:40Ignacio Rossicreate