bpo-37972: unittest.mock._Call now passes on __getitem__ to the __getattr__ chaining...
authorblhsing <github@ydooby.com>
Wed, 11 Sep 2019 14:28:06 +0000 (07:28 -0700)
committerMichael Foord <voidspace@users.noreply.github.com>
Wed, 11 Sep 2019 14:28:06 +0000 (16:28 +0200)
* 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__

Lib/unittest/mock.py
Lib/unittest/test/testmock/testhelpers.py
Misc/NEWS.d/next/Library/2019-08-28-21-40-12.bpo-37972.kP-n4L.rst [new file with mode: 0644]

index 50e495965519352b14a2aa0132962280c410e26c..a98decc2c9f008dcc5c73071c10bae0fee14efa5 100644 (file)
@@ -2462,6 +2462,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)
 
index 301bca430c131c5fcce7f8460ba9c2689f1c7b77..f3c7acb98c21fae241d07b8625bec8bf3219f2fd 100644 (file)
@@ -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 (file)
index 0000000..73d9ef7
--- /dev/null
@@ -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`:\r
+\r
+    call().foo().__getitem__('bar')\r
+\r
+Patch by blhsing\r