Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AttributeError on asserting autospecced mock object added using attach_mock #82654

Closed
tirkarthi opened this issue Oct 14, 2019 · 5 comments
Closed
Labels
3.7 (EOL) end of life 3.8 (EOL) end of life 3.9 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@tirkarthi
Copy link
Member

BPO 38473
Nosy @gpshead, @cjw296, @ned-deily, @voidspace, @ambv, @lisroach, @mariocj89, @tirkarthi
PRs
  • bpo-38473: Handle autospecced functions and methods used with attach_mock #16784
  • [3.7] bpo-38473: Handle autospecced functions and methods used with attach_mock (GH-16784) #18166
  • [3.8] bpo-38473: Handle autospecced functions and methods used with attach_mock (GH-16784) #18167
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2020-01-25.14:56:39.839>
    created_at = <Date 2019-10-14.14:25:09.791>
    labels = ['3.7', '3.8', 'type-bug', 'library', '3.9']
    title = 'AttributeError on asserting autospecced mock object added using attach_mock'
    updated_at = <Date 2020-01-25.14:56:39.838>
    user = 'https://github.com/tirkarthi'

    bugs.python.org fields:

    activity = <Date 2020-01-25.14:56:39.838>
    actor = 'xtreak'
    assignee = 'none'
    closed = True
    closed_date = <Date 2020-01-25.14:56:39.839>
    closer = 'xtreak'
    components = ['Library (Lib)']
    creation = <Date 2019-10-14.14:25:09.791>
    creator = 'xtreak'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 38473
    keywords = ['patch', '3.7regression', '3.8regression']
    message_count = 5.0
    messages = ['354635', '360616', '360688', '360689', '360690']
    nosy_count = 8.0
    nosy_names = ['gregory.p.smith', 'cjw296', 'ned.deily', 'michael.foord', 'lukasz.langa', 'lisroach', 'mariocj89', 'xtreak']
    pr_nums = ['16784', '18166', '18167']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue38473'
    versions = ['Python 3.7', 'Python 3.8', 'Python 3.9']

    @tirkarthi
    Copy link
    Member Author

    The following program causes AttributeError while retrieving the spec signature of a call. It seems that not all mocks specced should have _spec_signature where if autospec is used and the mock is attached with attach_mock then the "mock" attribute has the correct object from which _spec_signature has to be derived. On the attribute being not present we can fallback to the sig being None. This can be workaround by disabling autospec but since this is present in 3.7.5RC1 and 3.8.0RC1 I am tagging it as regression.

    I am also attaching a patch with script to reproduce this that should pass with the patch. I will try to make a PR tonight. Sorry for the last minute report I just stumbled upon this while debugging https://bugs.python.org/issue21478#msg354489. This change was introduced as part of https://bugs.python.org/issue36871 by me. I am tagging the nosy list from issue for review of the patch.

    import unittest
    from unittest.mock import patch, Mock, call, ANY
    
    
    class Foo:
        def set_foo(self, val): pass
    
    
    class FooTest(unittest.TestCase):
        @patch(f"{__name__}.Foo.set_foo", autospec=True)
        def test_autospec_attach_mock_assert(self, mock_set_foo):
            manager = Mock()
            manager.attach_mock(mock_set_foo, "set_foo_func")
            obj = Foo()
            obj.set_foo(3)
            manager.assert_has_calls([call.set_foo_func(ANY, 3)])
    
    if __name__ == "__main__":
        unittest.main()

    ➜ Python-3.7.5rc1 ./python autospec_regression.py
    E
    ======================================================================
    ERROR: test_autospec_attach_mock_assert (main.FooTest)
    ----------------------------------------------------------------------

    Traceback (most recent call last):
      File "/home/xtreak/Python-3.7.5rc1/Lib/unittest/mock.py", line 1255, in patched
        return func(*args, **keywargs)
      File "autospec_regression.py", line 16, in test_autospec_attach_mock_assert
        manager.assert_has_calls([call.set_foo_func(ANY, 3)])
      File "/home/xtreak/Python-3.7.5rc1/Lib/unittest/mock.py", line 897, in assert_has_calls
        expected = [self._call_matcher(c) for c in calls]
      File "/home/xtreak/Python-3.7.5rc1/Lib/unittest/mock.py", line 897, in <listcomp>
        expected = [self._call_matcher(c) for c in calls]
      File "/home/xtreak/Python-3.7.5rc1/Lib/unittest/mock.py", line 812, in _call_matcher
        sig = self._get_call_signature_from_name(_call[0])
      File "/home/xtreak/Python-3.7.5rc1/Lib/unittest/mock.py", line 798, in _get_call_signature_from_name
        sig = child._spec_signature
    AttributeError: 'function' object has no attribute '_spec_signature'

    Ran 1 test in 0.003s

    FAILED (errors=1)

    Patch :

    ➜  Python-3.7.5rc1 diff -u Lib/unittest/mock.py Lib/unittest/mock_patched.py
    --- Lib/unittest/mock.py	2019-10-01 22:53:17.000000000 +0530
    +++ Lib/unittest/mock_patched.py	2019-10-14 19:18:00.038416294 +0530
    @@ -795,7 +795,16 @@
                     break
                 else:
                     children = child._mock_children
    -                sig = child._spec_signature
    +                # If an autospecced object is attached using attach_mock the
    +                # child would be a function with mock object as attribute from
    +                # which signature has to be derived. If there is no signature
    +                # attribute then fallback to None to ensure old signature is 
    +                # not used.
    +                child = _extract_mock(child)
    +                try:
    +                    sig = child._spec_signature
    +                except AttributeError:
    +                    sig = None
     
             return sig

    @tirkarthi tirkarthi added 3.7 (EOL) end of life 3.8 (EOL) end of life 3.9 only security fixes stdlib Python modules in the Lib dir labels Oct 14, 2019
    @gpshead gpshead added the type-bug An unexpected behavior, bug, or error label Oct 14, 2019
    @cjw296
    Copy link
    Contributor

    cjw296 commented Jan 24, 2020

    New changeset 66b00a9 by Chris Withers (Karthikeyan Singaravelan) in branch 'master':
    bpo-38473: Handle autospecced functions and methods used with attach_mock (GH-16784)
    66b00a9

    @tirkarthi
    Copy link
    Member Author

    New changeset a5906b2 by Karthikeyan Singaravelan (Miss Islington (bot)) in branch '3.8':
    bpo-38473: Handle autospecced functions and methods used with attach_mock (GH-16784) (GH-18167)
    a5906b2

    @tirkarthi
    Copy link
    Member Author

    New changeset 71d2b33 by Karthikeyan Singaravelan (Miss Islington (bot)) in branch '3.7':
    bpo-38473: Handle autospecced functions and methods used with attach_mock (GH-16784) (bpo-18166)
    71d2b33

    @tirkarthi
    Copy link
    Member Author

    Thank you all for the review. Closing it as fixed.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life 3.8 (EOL) end of life 3.9 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants