[Python-checkins] gh-84753: Make inspect.iscoroutinefunction() work with AsyncMock (#94050)

ambv webhook-mailer at python.org
Thu Jun 30 13:08:43 EDT 2022


https://github.com/python/cpython/commit/4261b6bffc0b8bb5c6d4d80578a81b7520f4aefc
commit: 4261b6bffc0b8bb5c6d4d80578a81b7520f4aefc
branch: main
author: Mehdi ABAAKOUK <sileht at sileht.net>
committer: ambv <lukasz at langa.pl>
date: 2022-06-30T19:08:38+02:00
summary:

gh-84753: Make inspect.iscoroutinefunction() work with AsyncMock (#94050)

The inspect version was not working with unittest.mock.AsyncMock.

The fix introduces special-casing of AsyncMock in
`inspect.iscoroutinefunction` equivalent to the one
performed in `asyncio.iscoroutinefunction`.

Co-authored-by: Łukasz Langa <lukasz at langa.pl>

files:
A Misc/NEWS.d/next/Library/2022-06-21-11-40-31.gh-issue-84753.FW1pxO.rst
M Lib/inspect.py
M Lib/test/test_asyncio/test_tasks.py
M Lib/test/test_inspect.py
M Lib/unittest/mock.py

diff --git a/Lib/inspect.py b/Lib/inspect.py
index 6e744712f014b..cbc0632484b83 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -395,7 +395,7 @@ def _has_code_flag(f, flag):
     while ismethod(f):
         f = f.__func__
     f = functools._unwrap_partial(f)
-    if not isfunction(f):
+    if not (isfunction(f) or _signature_is_functionlike(f)):
         return False
     return bool(f.__code__.co_flags & flag)
 
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index 69cecb3ab1207..bde4defdf0129 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -1649,6 +1649,7 @@ async def fn2():
         self.assertTrue(asyncio.iscoroutinefunction(fn2))
 
         self.assertFalse(asyncio.iscoroutinefunction(mock.Mock()))
+        self.assertTrue(asyncio.iscoroutinefunction(mock.AsyncMock()))
 
     def test_coroutine_non_gen_function(self):
         async def func():
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index ae1842704d37d..be9f29e04ae11 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -202,6 +202,10 @@ def test_iscoroutine(self):
                     gen_coroutine_function_example))))
         self.assertTrue(inspect.isgenerator(gen_coro))
 
+        self.assertFalse(
+            inspect.iscoroutinefunction(unittest.mock.Mock()))
+        self.assertTrue(
+            inspect.iscoroutinefunction(unittest.mock.AsyncMock()))
         self.assertTrue(
             inspect.iscoroutinefunction(coroutine_function_example))
         self.assertTrue(
@@ -210,6 +214,10 @@ def test_iscoroutine(self):
                     coroutine_function_example))))
         self.assertTrue(inspect.iscoroutine(coro))
 
+        self.assertFalse(
+            inspect.isgeneratorfunction(unittest.mock.Mock()))
+        self.assertFalse(
+            inspect.isgeneratorfunction(unittest.mock.AsyncMock()))
         self.assertFalse(
             inspect.isgeneratorfunction(coroutine_function_example))
         self.assertFalse(
@@ -218,6 +226,12 @@ def test_iscoroutine(self):
                     coroutine_function_example))))
         self.assertFalse(inspect.isgenerator(coro))
 
+        self.assertFalse(
+            inspect.isasyncgenfunction(unittest.mock.Mock()))
+        self.assertFalse(
+            inspect.isasyncgenfunction(unittest.mock.AsyncMock()))
+        self.assertFalse(
+            inspect.isasyncgenfunction(coroutine_function_example))
         self.assertTrue(
             inspect.isasyncgenfunction(async_generator_function_example))
         self.assertTrue(
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 8262b7170b76b..cd46fea5162ab 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -2175,6 +2175,10 @@ def __init__(self, /, *args, **kwargs):
         code_mock = NonCallableMock(spec_set=CodeType)
         code_mock.co_flags = inspect.CO_COROUTINE
         self.__dict__['__code__'] = code_mock
+        self.__dict__['__name__'] = 'AsyncMock'
+        self.__dict__['__defaults__'] = tuple()
+        self.__dict__['__kwdefaults__'] = {}
+        self.__dict__['__annotations__'] = None
 
     async def _execute_mock_call(self, /, *args, **kwargs):
         # This is nearly just like super(), except for special handling
diff --git a/Misc/NEWS.d/next/Library/2022-06-21-11-40-31.gh-issue-84753.FW1pxO.rst b/Misc/NEWS.d/next/Library/2022-06-21-11-40-31.gh-issue-84753.FW1pxO.rst
new file mode 100644
index 0000000000000..f701d2a1afeb8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-06-21-11-40-31.gh-issue-84753.FW1pxO.rst
@@ -0,0 +1,3 @@
+:func:`inspect.iscoroutinefunction` now properly returns ``True`` when an instance
+of :class:`unittest.mock.AsyncMock` is passed to it.  This makes it consistent with
+behavior of :func:`asyncio.iscoroutinefunction`.  Patch by Mehdi ABAAKOUK.



More information about the Python-checkins mailing list