Skip to content

Can't call mocked methods after create_autospec() and seal() #91803

Closed

Description

@dseomn

Bug report

The code below raises the error below. If I'm understanding the documentation for mock.seal correctly, it's supposed to prevent the creation of new attributes on the sealed mock, not prevent calls to existing methods, right?

from unittest import mock
class Foo:
    def foo(self) -> int:
        return 0
foo = mock.create_autospec(Foo, instance=True)
mock.seal(foo)
foo.foo()
Traceback (most recent call last):
  File "/tmp/tmp.8toUu9Dy3T/foo.py", line 7, in <module>
    foo.foo()
  File "/usr/lib/python3.9/unittest/mock.py", line 1092, in __call__
    return self._mock_call(*args, **kwargs)
  File "/usr/lib/python3.9/unittest/mock.py", line 1096, in _mock_call
    return self._execute_mock_call(*args, **kwargs)
  File "/usr/lib/python3.9/unittest/mock.py", line 1168, in _execute_mock_call
    return self.return_value
  File "/usr/lib/python3.9/unittest/mock.py", line 630, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'return_value'

Your environment

  • CPython versions tested on: 3.9.9
  • Operating system and architecture: Debian testing / amd64

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Apr 21, 2022
  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Apr 21, 2022
  3. eugenetriguba commented on Apr 24, 2022

    @eugenetriguba
    Contributor

    If you set the return value beforehand or make a call to that method, you can.

    $ ./python
    Python 3.11.0a7+ (heads/main:090721721b, Apr 24 2022, 14:58:17) [GCC 11.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from unittest import mock
    >>> class Foo:
    ...     def foo(self) -> int:
    ...         return 0
    ... 
    >>> foo = mock.create_autospec(Foo, instance=True)
    >>> foo.foo.return_value = 1
    >>> mock.seal(foo)
    >>> foo.foo()
    1
    
    $ ./python
    Python 3.11.0a7+ (heads/main:090721721b, Apr 24 2022, 14:58:17) [GCC 11.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from unittest import mock
    >>> class Foo:
    ...     def foo(self) -> int:
    ...         return 0
    ... 
    >>> foo = mock.create_autospec(Foo, instance=True)
    >>> foo.foo()
    <MagicMock name='mock.foo()' id='140365640689440'>
    >>> mock.seal(foo)
    >>> foo.foo()
    <MagicMock name='mock.foo()' id='140365640689440'>
    

    This may be related to how mock.create_autospec is creating the mock. For instance:

    $ ./python
    Python 3.11.0a7+ (heads/main:090721721b, Apr 24 2022, 14:58:17) [GCC 11.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from unittest import mock
    >>> foo = mock.Mock()
    >>> def f(): return 1
    ... 
    >>> f()
    1
    >>> foo.foo = f
    >>> mock.seal(foo)
    >>> foo.foo()
    1
    

    I'll look into it a little more

  4. akulakov commented on May 3, 2022

    @akulakov
    Contributor

    I've added a draft PR #92213 , but I need to work on it a bit more.

  5. akulakov commented on May 3, 2022

    @akulakov
    Contributor

    I think the PR may be good, if we consider Mock return value of methods as part of the autospec. That's what such methods return if there is no seal.

    However I haven't used seal() before and I haven't used autospec in any advanced way, so I hope this can be looked at by an expert in mock module.

  6. added a commit that references this issue on Nov 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions