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

This commit is contained in:
Kumar Akshay 2019-03-22 13:40:40 +05:30 committed by Chris Withers
parent 40b6907b37
commit b0df45e55d
5 changed files with 51 additions and 11 deletions

View File

@ -609,9 +609,11 @@ the *new_callable* argument to :func:`patch`.
This is either ``None`` (if the mock hasn't been called), or the 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 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 form of a tuple: the first member, which can also be accessed through
was called with (or an empty tuple) and the second member is any the ``args`` property, is any ordered arguments the mock was
keyword arguments (or an empty dictionary). 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) >>> mock = Mock(return_value=None)
>>> print(mock.call_args) >>> print(mock.call_args)
@ -626,9 +628,17 @@ the *new_callable* argument to :func:`patch`.
call(3, 4) call(3, 4)
>>> mock.call_args == ((3, 4),) >>> mock.call_args == ((3, 4),)
True True
>>> mock.call_args.args
(3, 4)
>>> mock.call_args.kwargs
{}
>>> mock(3, 4, 5, key='fish', next='w00t!') >>> mock(3, 4, 5, key='fish', next='w00t!')
>>> mock.call_args >>> mock.call_args
call(3, 4, 5, key='fish', next='w00t!') 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:`call_args`, along with members of the lists :attr:`call_args_list`,
:attr:`method_calls` and :attr:`mock_calls` are :data:`call` objects. :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 = MagicMock(return_value=None)
>>> m(1, 2, 3, arg='one', arg2='two') >>> m(1, 2, 3, arg='one', arg2='two')
>>> kall = m.call_args >>> kall = m.call_args
>>> args, kwargs = kall >>> kall.args
>>> args
(1, 2, 3) (1, 2, 3)
>>> kwargs >>> kall.kwargs
{'arg': 'one', 'arg2': 'two'} {'arg': 'one', 'arg2': 'two'}
>>> args is kall[0] >>> kall.args is kall[0]
True True
>>> kwargs is kall[1] >>> kall.kwargs is kall[1]
True True
>>> m = MagicMock() >>> m = MagicMock()

View File

@ -2135,6 +2135,22 @@ class _Call(tuple):
def index(self, *args, **kwargs): def index(self, *args, **kwargs):
return self.__getattr__('index')(*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): def __repr__(self):
if not self._mock_from_kall: if not self._mock_from_kall:
name = self._mock_name or 'call' name = self._mock_name or 'call'

View File

@ -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, ('foo', (1, 2, 3), {})) self.assertEqual(args, ('foo', (1, 2, 3), {}))
self.assertEqual(args, ((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): 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, ('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),))
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, ('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, ((), 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): 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, ('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),))
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): def test_call_with_args_call_empty_name(self):
args = _Call(((1, 2, 3), {})) args = _Call(((1, 2, 3), {}))
self.assertEqual(args, call(1, 2, 3)) self.assertEqual(args, call(1, 2, 3))
self.assertEqual(call(1, 2, 3), args) self.assertEqual(call(1, 2, 3), args)
self.assertIn(call(1, 2, 3), [args]) self.assertIn(call(1, 2, 3), [args])

View File

@ -267,6 +267,10 @@ class MockTest(unittest.TestCase):
self.assertEqual(mock.call_count, 1, "call_count incoreect") self.assertEqual(mock.call_count, 1, "call_count incoreect")
self.assertEqual(mock.call_args, ((sentinel.Arg,), {}), self.assertEqual(mock.call_args, ((sentinel.Arg,), {}),
"call_args not set") "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,), {})], self.assertEqual(mock.call_args_list, [((sentinel.Arg,), {})],
"call_args_list not initialised correctly") "call_args_list not initialised correctly")
@ -300,6 +304,8 @@ class MockTest(unittest.TestCase):
]) ])
self.assertEqual(mock.call_args, self.assertEqual(mock.call_args,
((sentinel.Arg,), {"kw": sentinel.Kwarg})) ((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 # Comparing call_args to a long sequence should not raise
# an exception. See issue 24857. # an exception. See issue 24857.
@ -1157,9 +1163,8 @@ class MockTest(unittest.TestCase):
mock(2, b=4) mock(2, b=4)
self.assertEqual(len(mock.call_args), 2) self.assertEqual(len(mock.call_args), 2)
args, kwargs = mock.call_args self.assertEqual(mock.call_args.args, (2,))
self.assertEqual(args, (2,)) self.assertEqual(mock.call_args.kwargs, dict(b=4))
self.assertEqual(kwargs, dict(b=4))
expected_list = [((1,), dict(a=3)), ((2,), 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): for expected, call_args in zip(expected_list, mock.call_args_list):

View File

@ -0,0 +1 @@
Add ``args`` and ``kwargs`` properties to mock call objects. Contributed by Kumar Akshay.