Commit b0df45e5 authored by Kumar Akshay's avatar Kumar Akshay Committed by Chris Withers

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

parent 40b6907b
...@@ -609,9 +609,11 @@ the *new_callable* argument to :func:`patch`. ...@@ -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`. ...@@ -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: ...@@ -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()
......
...@@ -2135,6 +2135,22 @@ class _Call(tuple): ...@@ -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'
......
...@@ -146,6 +146,8 @@ class CallTest(unittest.TestCase): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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])
......
...@@ -267,6 +267,10 @@ class MockTest(unittest.TestCase): ...@@ -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): ...@@ -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): ...@@ -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):
......
Add ``args`` and ``kwargs`` properties to mock call objects. Contributed by Kumar Akshay.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment