From db0d8a5b2c803d30d9df436e00b6627ec8e09a13 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 12 Sep 2019 03:52:49 -0700 Subject: [PATCH] bpo-37972: unittest.mock._Call now passes on __getitem__ to the __getattr__ chaining so that call() can be subscriptable (GH-15565) (GH-15965) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bpo-37972: unittest.mock._Call now passes on __getitem__ to the __getattr__ chaining so that call() can be subscriptable * 📜🤖 Added by blurb_it. * Update 2019-08-28-21-40-12.bpo-37972.kP-n4L.rst added name of the contributor * bpo-37972: made all dunder methods chainable for _Call * bpo-37972: delegate only attributes of tuple instead to __getattr__ (cherry picked from commit 72c359912d36705a94fca8b63d80451905a14ae4) Co-authored-by: blhsing --- Lib/unittest/mock.py | 6 ++++++ Lib/unittest/test/testmock/testhelpers.py | 20 +++++++++++++++++++ .../2019-08-28-21-40-12.bpo-37972.kP-n4L.rst | 5 +++++ 3 files changed, 31 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2019-08-28-21-40-12.bpo-37972.kP-n4L.rst diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 7bfbfc92eef..cbc4d76b851 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -2464,6 +2464,12 @@ class _Call(tuple): return _Call(name=name, parent=self, from_kall=False) + def __getattribute__(self, attr): + if attr in tuple.__dict__: + raise AttributeError + return tuple.__getattribute__(self, attr) + + def count(self, /, *args, **kwargs): return self.__getattr__('count')(*args, **kwargs) diff --git a/Lib/unittest/test/testmock/testhelpers.py b/Lib/unittest/test/testmock/testhelpers.py index 301bca430c1..f3c7acb98c2 100644 --- a/Lib/unittest/test/testmock/testhelpers.py +++ b/Lib/unittest/test/testmock/testhelpers.py @@ -334,6 +334,26 @@ class CallTest(unittest.TestCase): self.assertEqual(_Call((('bar', 'barz'),),)[0], '') self.assertEqual(_Call((('bar', 'barz'), {'hello': 'world'}),)[0], '') + def test_dunder_call(self): + m = MagicMock() + m().foo()['bar']() + self.assertEqual( + m.mock_calls, + [call(), call().foo(), call().foo().__getitem__('bar'), call().foo().__getitem__()()] + ) + m = MagicMock() + m().foo()['bar'] = 1 + self.assertEqual( + m.mock_calls, + [call(), call().foo(), call().foo().__setitem__('bar', 1)] + ) + m = MagicMock() + iter(m().foo()) + self.assertEqual( + m.mock_calls, + [call(), call().foo(), call().foo().__iter__()] + ) + class SpecSignatureTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2019-08-28-21-40-12.bpo-37972.kP-n4L.rst b/Misc/NEWS.d/next/Library/2019-08-28-21-40-12.bpo-37972.kP-n4L.rst new file mode 100644 index 00000000000..73d9ef77762 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-08-28-21-40-12.bpo-37972.kP-n4L.rst @@ -0,0 +1,5 @@ +Subscripts to the `unittest.mock.call` objects now receive the same chaining mechanism as any other custom attributes, so that the following usage no longer raises a `TypeError`: + + call().foo().__getitem__('bar') + +Patch by blhsing