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

+13
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

+12-8
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

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)