Skip to content

Commit 71d2b33

Browse files
bpo-38473: Handle autospecced functions and methods used with attach_mock (GH-16784) (#18166)
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. (cherry picked from commit 66b00a9) Co-authored-by: Karthikeyan Singaravelan <[email protected]>
1 parent fd9ce2b commit 71d2b33

File tree

3 files changed

+35
-0
lines changed

3 files changed

+35
-0
lines changed

Lib/unittest/mock.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,10 @@ def _get_call_signature_from_name(self, name):
794794
if child is None or isinstance(child, _SpecState):
795795
break
796796
else:
797+
# If an autospecced object is attached using attach_mock the
798+
# child would be a function with mock object as attribute from
799+
# which signature has to be derived.
800+
child = _extract_mock(child)
797801
children = child._mock_children
798802
sig = child._spec_signature
799803

Lib/unittest/test/testmock/testmock.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,35 @@ def test_attach_mock_patch_autospec(self):
18631863
self.assertEqual(mock_func.mock._extract_mock_name(), 'mock.child')
18641864

18651865

1866+
def test_attach_mock_patch_autospec_signature(self):
1867+
with mock.patch(f'{__name__}.Something.meth', autospec=True) as mocked:
1868+
manager = Mock()
1869+
manager.attach_mock(mocked, 'attach_meth')
1870+
obj = Something()
1871+
obj.meth(1, 2, 3, d=4)
1872+
manager.assert_has_calls([call.attach_meth(mock.ANY, 1, 2, 3, d=4)])
1873+
obj.meth.assert_has_calls([call(mock.ANY, 1, 2, 3, d=4)])
1874+
mocked.assert_has_calls([call(mock.ANY, 1, 2, 3, d=4)])
1875+
1876+
with mock.patch(f'{__name__}.something', autospec=True) as mocked:
1877+
manager = Mock()
1878+
manager.attach_mock(mocked, 'attach_func')
1879+
something(1)
1880+
manager.assert_has_calls([call.attach_func(1)])
1881+
something.assert_has_calls([call(1)])
1882+
mocked.assert_has_calls([call(1)])
1883+
1884+
with mock.patch(f'{__name__}.Something', autospec=True) as mocked:
1885+
manager = Mock()
1886+
manager.attach_mock(mocked, 'attach_obj')
1887+
obj = Something()
1888+
obj.meth(1, 2, 3, d=4)
1889+
manager.assert_has_calls([call.attach_obj(),
1890+
call.attach_obj().meth(1, 2, 3, d=4)])
1891+
obj.meth.assert_has_calls([call(1, 2, 3, d=4)])
1892+
mocked.assert_has_calls([call(), call().meth(1, 2, 3, d=4)])
1893+
1894+
18661895
def test_attribute_deletion(self):
18671896
for mock in (Mock(), MagicMock(), NonCallableMagicMock(),
18681897
NonCallableMock()):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Use signature from inner mock for autospecced methods attached with
2+
:func:`unittest.mock.attach_mock`. Patch by Karthikeyan Singaravelan.

0 commit comments

Comments
 (0)