From b0df45e55dc8304bac0e3cad0225472b84190964 Mon Sep 17 00:00:00 2001 From: Kumar Akshay Date: Fri, 22 Mar 2019 13:40:40 +0530 Subject: [PATCH] bpo-21269: Provide args and kwargs attributes on mock call objects GH11807 --- Doc/library/unittest.mock.rst | 25 +++++++++++++------ Lib/unittest/mock.py | 16 ++++++++++++ Lib/unittest/test/testmock/testhelpers.py | 9 +++++++ Lib/unittest/test/testmock/testmock.py | 11 +++++--- .../2019-02-10-16-49-16.bpo-21269.Fqi7VH.rst | 1 + 5 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-02-10-16-49-16.bpo-21269.Fqi7VH.rst diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index ff7a54c51fb..ed00ee6d0c2 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 2ccf0d82ce2..fdde16be03a 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -2135,6 +2135,22 @@ class _Call(tuple): 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 745580ef79d..9f1bf2676bf 100644 --- a/Lib/unittest/test/testmock/testhelpers.py +++ b/Lib/unittest/test/testmock/testhelpers.py @@ -146,6 +146,8 @@ class CallTest(unittest.TestCase): 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 @@ class CallTest(unittest.TestCase): 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 @@ class CallTest(unittest.TestCase): 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 @@ class CallTest(unittest.TestCase): 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 @@ class CallTest(unittest.TestCase): 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 2ad90ea81ec..66a5720d143 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -267,6 +267,10 @@ class MockTest(unittest.TestCase): 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 @@ class MockTest(unittest.TestCase): ]) 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 @@ class MockTest(unittest.TestCase): 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 00000000000..15ad636a5e8 --- /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.