Issue 36598: mock side_effect should be checked for iterable not callable (original) (raw)

Created on 2019-04-11 04:12 by jazzblue, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (4)
msg339923 - (view) Author: Gregory Ronin (jazzblue) Date: 2019-04-11 04:12
In mock.py, in method: def _mock_call(_mock_self, *args, **kwargs): There is a following piece of code: if not _callable(effect): result = next(effect) if _is_exception(result): raise result if result is DEFAULT: result = self.return_value return result ret_val = effect(*args, **kwargs) This works correctly for iterables (such as lists) that are not defined as generators. However, if one defined a generator as a function this would not work. It seems like the check should be not for callable, but for iterable: try: iter(effect) except TypeError: # If not iterable then callable or exception if _callable(effect): ret_val = effect(*args, **kwargs) else: raise effect else: # Iterable result = next(effect) if _is_exception(result): raise result if result is DEFAULT: result = self.return_value return result
msg339927 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2019-04-11 06:07
I am not sure if the snippets you are referring to are from testing-cabal/mock repo which could be different from master branch. Current code is at [0] if effect is not None: if _is_exception(effect): raise effect elif not _callable(effect): result = next(effect) if _is_exception(result): raise result else: result = effect(*args, **kwargs) if result is not DEFAULT: return result > This works correctly for iterables (such as lists) that are not defined as generators. However, if one defined a generator as a function this would not work. This does seem to work for generator function as below. Sorry, maybe I am getting it wrong with respect to terminologies and understanding the issue. Can you add a short script around what you are expecting? $ cat ../backups/bpo36598.py from unittest.mock import patch def gen(i): while i < 5: yield i i += 1 def foo(): return 1 with patch('__main__.foo', side_effect=gen(0)): for _ in range(2): print(foo()) for _ in range(2): print(foo()) $ ./python.exe ../backups/bpo36598.py 0 1 2 3 [0] https://github.com/python/cpython/blob/a9bd8925c7fa50dd3cfab125b824ec192133ef49/Lib/unittest/mock.py#L1043
msg339992 - (view) Author: Gregory Ronin (jazzblue) Date: 2019-04-11 18:30
You are right. I was not calling generator the right way in mock. After I tried your suggestion it works.
msg340018 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2019-04-12 10:09
Thanks, I am closing this as not a bug. Feel free to reopen this if I have missed any.
History
Date User Action Args
2022-04-11 14:59:13 admin set github: 80779
2019-04-12 10:09:13 xtreak set status: open -> closedresolution: not a bugmessages: + stage: patch review -> resolved
2019-04-11 18:30:40 jazzblue set messages: +
2019-04-11 16:55:28 xtreak set pull_requests: - <pull%5Frequest12717>
2019-04-11 16:53:28 xtreak set keywords: + patchstage: patch reviewpull_requests: + <pull%5Frequest12717>
2019-04-11 06:07:46 xtreak set messages: +
2019-04-11 05:32:52 xtreak set nosy: + xtreakversions: + Python 3.8, - Python 2.7
2019-04-11 04:12:58 jazzblue create