]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-90848: Fixed create_autospec ignoring configure_mock style kwargs (#118163)
authorinfohash <46137868+infohash@users.noreply.github.com>
Thu, 2 May 2024 17:36:35 +0000 (23:06 +0530)
committerGitHub <noreply@github.com>
Thu, 2 May 2024 17:36:35 +0000 (18:36 +0100)
Lib/test/test_unittest/testmock/testmock.py
Lib/unittest/mock.py
Misc/NEWS.d/next/Library/2024-04-22-21-54-12.gh-issue-90848.5jHEEc.rst [new file with mode: 0644]

index b81b3049d56bf82ff434484b608dcce71bc4cc61..77f6f1eb4b76b9538049b5a066e75375bb2f1475 100644 (file)
@@ -115,6 +115,19 @@ class MockTest(unittest.TestCase):
         with self.assertRaises(TypeError):
             mock()
 
+    def test_create_autospec_should_be_configurable_by_kwargs(self):
+        """If kwargs are given to configure mock, the function must configure
+        the parent mock during initialization."""
+        mocked_result = 'mocked value'
+        class_mock = create_autospec(spec=Something, **{
+            'return_value.meth.side_effect': [ValueError, DEFAULT],
+            'return_value.meth.return_value': mocked_result})
+        with self.assertRaises(ValueError):
+            class_mock().meth(a=None, b=None, c=None)
+        self.assertEqual(class_mock().meth(a=None, b=None, c=None), mocked_result)
+        # Only the parent mock should be configurable because the user will
+        # pass kwargs with respect to the parent mock.
+        self.assertEqual(class_mock().return_value.meth.side_effect, None)
 
     def test_repr(self):
         mock = Mock(name='foo')
index 1799e9bbf58592fc4d0a2802580c56682a0e9e09..a2634b6164062a87954fc2bc9dc36accda529e6d 100644 (file)
@@ -2788,8 +2788,8 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
     if _parent is not None and not instance:
         _parent._mock_children[_name] = mock
 
-    wrapped = kwargs.get('wraps')
-
+    # Pop wraps from kwargs because it must not be passed to configure_mock.
+    wrapped = kwargs.pop('wraps', None)
     if is_type and not instance and 'return_value' not in kwargs:
         mock.return_value = create_autospec(spec, spec_set, instance=True,
                                             _name='()', _parent=mock,
@@ -2814,12 +2814,12 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
         except AttributeError:
             continue
 
-        kwargs = {'spec': original}
+        child_kwargs = {'spec': original}
         # Wrap child attributes also.
         if wrapped and hasattr(wrapped, entry):
-            kwargs.update(wraps=original)
+            child_kwargs.update(wraps=original)
         if spec_set:
-            kwargs = {'spec_set': original}
+            child_kwargs = {'spec_set': original}
 
         if not isinstance(original, FunctionTypes):
             new = _SpecState(original, spec_set, mock, entry, instance)
@@ -2830,14 +2830,13 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
                 parent = mock.mock
 
             skipfirst = _must_skip(spec, entry, is_type)
-            kwargs['_eat_self'] = skipfirst
+            child_kwargs['_eat_self'] = skipfirst
             if iscoroutinefunction(original):
                 child_klass = AsyncMock
             else:
                 child_klass = MagicMock
             new = child_klass(parent=parent, name=entry, _new_name=entry,
-                              _new_parent=parent,
-                              **kwargs)
+                              _new_parent=parent, **child_kwargs)
             mock._mock_children[entry] = new
             new.return_value = child_klass()
             _check_signature(original, new, skipfirst=skipfirst)
@@ -2848,6 +2847,11 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
         # setting as an instance attribute?
         if isinstance(new, FunctionTypes):
             setattr(mock, entry, new)
+    # kwargs are passed with respect to the parent mock so, they are not used
+    # for creating return_value of the parent mock. So, this condition
+    # should be true only for the parent mock if kwargs are given.
+    if _is_instance_mock(mock) and kwargs:
+        mock.configure_mock(**kwargs)
 
     return mock
 
diff --git a/Misc/NEWS.d/next/Library/2024-04-22-21-54-12.gh-issue-90848.5jHEEc.rst b/Misc/NEWS.d/next/Library/2024-04-22-21-54-12.gh-issue-90848.5jHEEc.rst
new file mode 100644 (file)
index 0000000..adbca01
--- /dev/null
@@ -0,0 +1 @@
+Fixed :func:`unittest.mock.create_autospec` to configure parent mock with keyword arguments.