]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-90848: Fixed create_autospec ignoring configure_mock style kwargs (GH-11816...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 2 May 2024 18:01:17 +0000 (20:01 +0200)
committerGitHub <noreply@github.com>
Thu, 2 May 2024 18:01:17 +0000 (18:01 +0000)
gh-90848: Fixed create_autospec ignoring configure_mock style kwargs (GH-118163)
(cherry picked from commit b28a3339e4c63ea3a801dba9bbbc6af5af42c3a0)

Co-authored-by: infohash <46137868+infohash@users.noreply.github.com>
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 3fb4f1f866b9357a159f44a02e477884b59cb9d1..165e2c044d8c5a12d9bfceab3b51aa6c2ed597c4 100644 (file)
@@ -104,6 +104,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 0e1b9ace7bf0b6742a3094650bdd5f9ee7f53fcc..486e0c634b82c152774e4ea27a0089e018ac6364 100644 (file)
@@ -2757,8 +2757,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,
@@ -2783,12 +2783,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)
@@ -2799,14 +2799,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)
@@ -2817,6 +2816,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.