bpo-37251: Removes __code__ check from _is_async_obj. (GH-15830)
authorLisa Roach <lisaroach14@gmail.com>
Tue, 10 Sep 2019 11:18:40 +0000 (12:18 +0100)
committerGitHub <noreply@github.com>
Tue, 10 Sep 2019 11:18:40 +0000 (12:18 +0100)
Lib/unittest/mock.py
Lib/unittest/test/testmock/testasync.py
Misc/NEWS.d/next/Library/2019-09-10-10-59-50.bpo-37251.8zn2o3.rst [new file with mode: 0644]

index c26b367a4dc290de8406c843509cd5b0e13aef46..50e495965519352b14a2aa0132962280c410e26c 100644 (file)
@@ -46,10 +46,9 @@ FILTER_DIR = True
 _safe_super = super
 
 def _is_async_obj(obj):
-    if getattr(obj, '__code__', None):
-        return asyncio.iscoroutinefunction(obj) or inspect.isawaitable(obj)
-    else:
+    if _is_instance_mock(obj) and not isinstance(obj, AsyncMock):
         return False
+    return asyncio.iscoroutinefunction(obj) or inspect.isawaitable(obj)
 
 
 def _is_async_func(func):
index 865cfdc0026465f936eb440cc47f178a4aacbb33..550234223cc372fef73a9c56caa10f72b1754e71 100644 (file)
@@ -18,6 +18,10 @@ class AsyncClass:
     def normal_method(self):
         pass
 
+class AwaitableClass:
+    def __await__(self):
+        yield
+
 async def async_func():
     pass
 
@@ -160,6 +164,10 @@ class AsyncAutospecTest(unittest.TestCase):
         with self.assertRaises(RuntimeError):
             create_autospec(async_func, instance=True)
 
+    def test_create_autospec_awaitable_class(self):
+        awaitable_mock = create_autospec(spec=AwaitableClass())
+        self.assertIsInstance(create_autospec(awaitable_mock), AsyncMock)
+
     def test_create_autospec(self):
         spec = create_autospec(async_func_args)
         awaitable = spec(1, 2, c=3)
@@ -321,6 +329,13 @@ class AsyncSpecSetTest(unittest.TestCase):
         self.assertIsInstance(mock.normal_method, MagicMock)
         self.assertIsInstance(mock, MagicMock)
 
+    def test_magicmock_lambda_spec(self):
+        mock_obj = MagicMock()
+        mock_obj.mock_func = MagicMock(spec=lambda x: x)
+
+        with patch.object(mock_obj, "mock_func") as cm:
+            self.assertIsInstance(cm, MagicMock)
+
 
 class AsyncArguments(unittest.TestCase):
     def test_add_return_value(self):
diff --git a/Misc/NEWS.d/next/Library/2019-09-10-10-59-50.bpo-37251.8zn2o3.rst b/Misc/NEWS.d/next/Library/2019-09-10-10-59-50.bpo-37251.8zn2o3.rst
new file mode 100644 (file)
index 0000000..27fd1e4
--- /dev/null
@@ -0,0 +1,3 @@
+Remove `__code__` check in AsyncMock that incorrectly
+evaluated function specs as async objects but failed to evaluate classes
+with `__await__` but no `__code__` attribute defined as async objects.