Skip to content

Commit b28a333

Browse files
authored
gh-90848: Fixed create_autospec ignoring configure_mock style kwargs (#118163)
1 parent 6bcbee0 commit b28a333

File tree

3 files changed

+26
-8
lines changed

3 files changed

+26
-8
lines changed

Lib/test/test_unittest/testmock/testmock.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,19 @@ def f(): pass
115115
with self.assertRaises(TypeError):
116116
mock()
117117

118+
def test_create_autospec_should_be_configurable_by_kwargs(self):
119+
"""If kwargs are given to configure mock, the function must configure
120+
the parent mock during initialization."""
121+
mocked_result = 'mocked value'
122+
class_mock = create_autospec(spec=Something, **{
123+
'return_value.meth.side_effect': [ValueError, DEFAULT],
124+
'return_value.meth.return_value': mocked_result})
125+
with self.assertRaises(ValueError):
126+
class_mock().meth(a=None, b=None, c=None)
127+
self.assertEqual(class_mock().meth(a=None, b=None, c=None), mocked_result)
128+
# Only the parent mock should be configurable because the user will
129+
# pass kwargs with respect to the parent mock.
130+
self.assertEqual(class_mock().return_value.meth.side_effect, None)
118131

119132
def test_repr(self):
120133
mock = Mock(name='foo')

Lib/unittest/mock.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2788,8 +2788,8 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
27882788
if _parent is not None and not instance:
27892789
_parent._mock_children[_name] = mock
27902790

2791-
wrapped = kwargs.get('wraps')
2792-
2791+
# Pop wraps from kwargs because it must not be passed to configure_mock.
2792+
wrapped = kwargs.pop('wraps', None)
27932793
if is_type and not instance and 'return_value' not in kwargs:
27942794
mock.return_value = create_autospec(spec, spec_set, instance=True,
27952795
_name='()', _parent=mock,
@@ -2814,12 +2814,12 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
28142814
except AttributeError:
28152815
continue
28162816

2817-
kwargs = {'spec': original}
2817+
child_kwargs = {'spec': original}
28182818
# Wrap child attributes also.
28192819
if wrapped and hasattr(wrapped, entry):
2820-
kwargs.update(wraps=original)
2820+
child_kwargs.update(wraps=original)
28212821
if spec_set:
2822-
kwargs = {'spec_set': original}
2822+
child_kwargs = {'spec_set': original}
28232823

28242824
if not isinstance(original, FunctionTypes):
28252825
new = _SpecState(original, spec_set, mock, entry, instance)
@@ -2830,14 +2830,13 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
28302830
parent = mock.mock
28312831

28322832
skipfirst = _must_skip(spec, entry, is_type)
2833-
kwargs['_eat_self'] = skipfirst
2833+
child_kwargs['_eat_self'] = skipfirst
28342834
if iscoroutinefunction(original):
28352835
child_klass = AsyncMock
28362836
else:
28372837
child_klass = MagicMock
28382838
new = child_klass(parent=parent, name=entry, _new_name=entry,
2839-
_new_parent=parent,
2840-
**kwargs)
2839+
_new_parent=parent, **child_kwargs)
28412840
mock._mock_children[entry] = new
28422841
new.return_value = child_klass()
28432842
_check_signature(original, new, skipfirst=skipfirst)
@@ -2848,6 +2847,11 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
28482847
# setting as an instance attribute?
28492848
if isinstance(new, FunctionTypes):
28502849
setattr(mock, entry, new)
2850+
# kwargs are passed with respect to the parent mock so, they are not used
2851+
# for creating return_value of the parent mock. So, this condition
2852+
# should be true only for the parent mock if kwargs are given.
2853+
if _is_instance_mock(mock) and kwargs:
2854+
mock.configure_mock(**kwargs)
28512855

28522856
return mock
28532857

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed :func:`unittest.mock.create_autospec` to configure parent mock with keyword arguments.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy