classification
Title: Mocking a MagicMock with a function spec results in an AsyncMock
Type: behavior Stage: patch review
Components: Library (Lib) Versions: Python 3.9, Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: hroncok, jcline, lisroach, mariocj89, xtreak
Priority: normal Keywords: patch

Created on 2019-06-12 14:00 by jcline, last changed 2019-06-15 16:53 by xtreak.

Pull Requests
URL Status Linked Edit
PR 14117 open xtreak, 2019-06-15 16:34
Messages (4)
msg345358 - (view) Author: Jeremy Cline (jcline) * Date: 2019-06-12 14:00
This is related to the new AsyncMock[0] class in Python 3.8b1. A simple reproducer is:

from unittest import mock

mock_obj = mock.MagicMock()
mock_obj.mock_func = mock.MagicMock(spec=lambda x: x)

with mock.patch.object(mock_obj, "mock_func") as nested:
    print(type(nested))


Instead of a MagicMock (the behavior in Python 3.7) in Python 3.8b1 this results in an AsyncMock.

[0]https://github.com/python/cpython/pull/9296
msg345377 - (view) Author: Lisa Roach (lisroach) * (Python committer) Date: 2019-06-12 16:14
Following up from xtreak's proposal (https://github.com/python/cpython/pull/9296) I think checking if __code__ is actually a CodeType is a good idea. It's simple and doesn't change any other functionality in an unwanted way.
msg345399 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python triager) Date: 2019-06-12 18:16
I will wait for a couple of days for suggestions and will raise a PR to check for __code__ to be a CodeType. Thanks.
msg345704 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python triager) Date: 2019-06-15 16:53
I created PR to ensure the __code__ object is checked to be a CodeType and converted the report to a unittest. I also found a similar function _is_async_func [0] which also seems to perform similar check but is used only in create_autospec. creating an autospec function out of MagicMock with a function spec is not possible so though the change could be made it's not testable. Also changing _is_async_func to _is_async_obj in create_autospec shows no test case failure. Can this be removed to use only _is_async_obj? Is there a difference in their usage due to isawaitable check present in _is_async_obj that needs a test?

# create_autospec with MagicMock(spec=lambda x: x)

$ cpython git:(bpo37251) ./python.exe
Python 3.9.0a0 (heads/master:7a68f8c28b, Jun 15 2019, 21:00:05)
[Clang 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from unittest.mock import *
>>> create_autospec(MagicMock())
<MagicMock spec='MagicMock' id='4370353280'>
>>> create_autospec(MagicMock(spec=lambda x: x))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", line 2547, in create_autospec
    mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name,
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", line 2066, in __init__
    super().__init__(*args, **kwargs)
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", line 1996, in __init__
    _safe_super(AsyncMagicMixin, self).__init__(*args, **kw)
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", line 1007, in __init__
    _safe_super(CallableMixin, self).__init__(
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", line 442, in __init__
    self._mock_add_spec(spec, spec_set, _spec_as_instance, _eat_self)
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", line 503, in _mock_add_spec
    res = _get_signature_object(spec,
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", line 99, in _get_signature_object
    return func, inspect.signature(sig_func)
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/inspect.py", line 3093, in signature
    return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/inspect.py", line 2842, in from_callable
    return _signature_from_callable(obj, sigcls=cls,
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/inspect.py", line 2292, in _signature_from_callable
    return _signature_from_function(sigcls, obj,
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/inspect.py", line 2175, in _signature_from_function
    parameters.append(Parameter(name, annotation=annotation,
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/inspect.py", line 2495, in __init__
    raise TypeError(msg)
TypeError: name must be a str, not a MagicMock


[0] https://github.com/python/cpython/blob/3a1d50e7e573efb577714146bed5c03b9c95f466/Lib/unittest/mock.py#L55
History
Date User Action Args
2019-06-15 16:53:06xtreaksetmessages: + msg345704
versions: + Python 3.9
2019-06-15 16:34:36xtreaksetkeywords: + patch
stage: patch review
pull_requests: + pull_request13967
2019-06-12 18:16:29xtreaksetmessages: + msg345399
2019-06-12 16:14:41lisroachsetmessages: + msg345377
2019-06-12 15:05:33hroncoksetnosy: + hroncok
2019-06-12 14:11:44mariocj89setnosy: + mariocj89
2019-06-12 14:06:24xtreaksetnosy: + lisroach, xtreak
2019-06-12 14:00:18jclinecreate