[Python-checkins] bpo-21269: Provide args and kwargs attributes on mock call objects GH11807

Chris Withers webhook-mailer at python.org
Fri Mar 22 04:10:50 EDT 2019


https://github.com/python/cpython/commit/b0df45e55dc8304bac0e3cad0225472b84190964
commit: b0df45e55dc8304bac0e3cad0225472b84190964
branch: master
author: Kumar Akshay <k.akshay9721 at gmail.com>
committer: Chris Withers <chris at withers.org>
date: 2019-03-22T08:10:40Z
summary:

bpo-21269: Provide args and kwargs attributes on mock call objects GH11807

files:
A Misc/NEWS.d/next/Library/2019-02-10-16-49-16.bpo-21269.Fqi7VH.rst
M Doc/library/unittest.mock.rst
M Lib/unittest/mock.py
M Lib/unittest/test/testmock/testhelpers.py
M Lib/unittest/test/testmock/testmock.py

diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst
index ff7a54c51fba..ed00ee6d0c2d 100644
--- a/Doc/library/unittest.mock.rst
+++ b/Doc/library/unittest.mock.rst
@@ -609,9 +609,11 @@ the *new_callable* argument to :func:`patch`.
 
         This is either ``None`` (if the mock hasn't been called), or the
         arguments that the mock was last called with. This will be in the
-        form of a tuple: the first member is any ordered arguments the mock
-        was called with (or an empty tuple) and the second member is any
-        keyword arguments (or an empty dictionary).
+        form of a tuple: the first member, which can also be accessed through
+        the ``args`` property, is any ordered arguments the mock was
+        called with (or an empty tuple) and the second member, which can
+        also be accessed through the ``kwargs`` property, is any keyword
+        arguments (or an empty dictionary).
 
             >>> mock = Mock(return_value=None)
             >>> print(mock.call_args)
@@ -626,9 +628,17 @@ the *new_callable* argument to :func:`patch`.
             call(3, 4)
             >>> mock.call_args == ((3, 4),)
             True
+            >>> mock.call_args.args
+            (3, 4)
+            >>> mock.call_args.kwargs
+            {}
             >>> mock(3, 4, 5, key='fish', next='w00t!')
             >>> mock.call_args
             call(3, 4, 5, key='fish', next='w00t!')
+            >>> mock.call_args.args
+            (3, 4, 5)
+            >>> mock.call_args.kwargs
+            {'key': 'fish', 'next': 'w00t!'}
 
         :attr:`call_args`, along with members of the lists :attr:`call_args_list`,
         :attr:`method_calls` and :attr:`mock_calls` are :data:`call` objects.
@@ -1987,14 +1997,13 @@ arguments are a dictionary:
     >>> m = MagicMock(return_value=None)
     >>> m(1, 2, 3, arg='one', arg2='two')
     >>> kall = m.call_args
-    >>> args, kwargs = kall
-    >>> args
+    >>> kall.args
     (1, 2, 3)
-    >>> kwargs
+    >>> kall.kwargs
     {'arg': 'one', 'arg2': 'two'}
-    >>> args is kall[0]
+    >>> kall.args is kall[0]
     True
-    >>> kwargs is kall[1]
+    >>> kall.kwargs is kall[1]
     True
 
     >>> m = MagicMock()
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 2ccf0d82ce23..fdde16be03a3 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -2135,6 +2135,22 @@ def count(self, *args, **kwargs):
     def index(self, *args, **kwargs):
         return self.__getattr__('index')(*args, **kwargs)
 
+    def _get_call_arguments(self):
+        if len(self) == 2:
+            args, kwargs = self
+        else:
+            name, args, kwargs = self
+
+        return args, kwargs
+
+    @property
+    def args(self):
+        return self._get_call_arguments()[0]
+
+    @property
+    def kwargs(self):
+        return self._get_call_arguments()[1]
+
     def __repr__(self):
         if not self._mock_from_kall:
             name = self._mock_name or 'call'
diff --git a/Lib/unittest/test/testmock/testhelpers.py b/Lib/unittest/test/testmock/testhelpers.py
index 745580ef79db..9f1bf2676bf5 100644
--- a/Lib/unittest/test/testmock/testhelpers.py
+++ b/Lib/unittest/test/testmock/testhelpers.py
@@ -146,6 +146,8 @@ def test_call_with_args(self):
         self.assertEqual(args, ('foo', (1, 2, 3)))
         self.assertEqual(args, ('foo', (1, 2, 3), {}))
         self.assertEqual(args, ((1, 2, 3), {}))
+        self.assertEqual(args.args, (1, 2, 3))
+        self.assertEqual(args.kwargs, {})
 
 
     def test_named_call_with_args(self):
@@ -153,6 +155,8 @@ def test_named_call_with_args(self):
 
         self.assertEqual(args, ('foo', (1, 2, 3)))
         self.assertEqual(args, ('foo', (1, 2, 3), {}))
+        self.assertEqual(args.args, (1, 2, 3))
+        self.assertEqual(args.kwargs, {})
 
         self.assertNotEqual(args, ((1, 2, 3),))
         self.assertNotEqual(args, ((1, 2, 3), {}))
@@ -165,6 +169,8 @@ def test_call_with_kwargs(self):
         self.assertEqual(args, ('foo', dict(a=3, b=4)))
         self.assertEqual(args, ('foo', (), dict(a=3, b=4)))
         self.assertEqual(args, ((), dict(a=3, b=4)))
+        self.assertEqual(args.args, ())
+        self.assertEqual(args.kwargs, dict(a=3, b=4))
 
 
     def test_named_call_with_kwargs(self):
@@ -172,6 +178,8 @@ def test_named_call_with_kwargs(self):
 
         self.assertEqual(args, ('foo', dict(a=3, b=4)))
         self.assertEqual(args, ('foo', (), dict(a=3, b=4)))
+        self.assertEqual(args.args, ())
+        self.assertEqual(args.kwargs, dict(a=3, b=4))
 
         self.assertNotEqual(args, (dict(a=3, b=4),))
         self.assertNotEqual(args, ((), dict(a=3, b=4)))
@@ -179,6 +187,7 @@ def test_named_call_with_kwargs(self):
 
     def test_call_with_args_call_empty_name(self):
         args = _Call(((1, 2, 3), {}))
+
         self.assertEqual(args, call(1, 2, 3))
         self.assertEqual(call(1, 2, 3), args)
         self.assertIn(call(1, 2, 3), [args])
diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py
index 2ad90ea81ec7..66a5720d1432 100644
--- a/Lib/unittest/test/testmock/testmock.py
+++ b/Lib/unittest/test/testmock/testmock.py
@@ -267,6 +267,10 @@ def test_call(self):
         self.assertEqual(mock.call_count, 1, "call_count incoreect")
         self.assertEqual(mock.call_args, ((sentinel.Arg,), {}),
                          "call_args not set")
+        self.assertEqual(mock.call_args.args, (sentinel.Arg,),
+                         "call_args not set")
+        self.assertEqual(mock.call_args.kwargs, {},
+                         "call_args not set")
         self.assertEqual(mock.call_args_list, [((sentinel.Arg,), {})],
                          "call_args_list not initialised correctly")
 
@@ -300,6 +304,8 @@ def test_call_args_comparison(self):
         ])
         self.assertEqual(mock.call_args,
                          ((sentinel.Arg,), {"kw": sentinel.Kwarg}))
+        self.assertEqual(mock.call_args.args, (sentinel.Arg,))
+        self.assertEqual(mock.call_args.kwargs, {"kw": sentinel.Kwarg})
 
         # Comparing call_args to a long sequence should not raise
         # an exception. See issue 24857.
@@ -1157,9 +1163,8 @@ def test_call_args_two_tuple(self):
         mock(2, b=4)
 
         self.assertEqual(len(mock.call_args), 2)
-        args, kwargs = mock.call_args
-        self.assertEqual(args, (2,))
-        self.assertEqual(kwargs, dict(b=4))
+        self.assertEqual(mock.call_args.args, (2,))
+        self.assertEqual(mock.call_args.kwargs, dict(b=4))
 
         expected_list = [((1,), dict(a=3)), ((2,), dict(b=4))]
         for expected, call_args in zip(expected_list, mock.call_args_list):
diff --git a/Misc/NEWS.d/next/Library/2019-02-10-16-49-16.bpo-21269.Fqi7VH.rst b/Misc/NEWS.d/next/Library/2019-02-10-16-49-16.bpo-21269.Fqi7VH.rst
new file mode 100644
index 000000000000..15ad636a5e80
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-02-10-16-49-16.bpo-21269.Fqi7VH.rst
@@ -0,0 +1 @@
+Add ``args`` and ``kwargs`` properties to mock call objects. Contributed by Kumar Akshay.



More information about the Python-checkins mailing list