Skip to content

Commit 47f23b2

Browse files
gh-84753: Make inspect.iscoroutinefunction() work with AsyncMock (GH-94050) (GH-94461)
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 <[email protected]> (cherry picked from commit 4261b6b) Co-authored-by: Mehdi ABAAKOUK <[email protected]>
1 parent d915ed2 commit 47f23b2

File tree

5 files changed

+23
-1
lines changed

5 files changed

+23
-1
lines changed

Lib/inspect.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ def _has_code_flag(f, flag):
294294
while ismethod(f):
295295
f = f.__func__
296296
f = functools._unwrap_partial(f)
297-
if not isfunction(f):
297+
if not (isfunction(f) or _signature_is_functionlike(f)):
298298
return False
299299
return bool(f.__code__.co_flags & flag)
300300

Lib/test/test_asyncio/test_tasks.py

+1
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,7 @@ def fn2():
17231723
self.assertTrue(asyncio.iscoroutinefunction(fn2))
17241724

17251725
self.assertFalse(asyncio.iscoroutinefunction(mock.Mock()))
1726+
self.assertTrue(asyncio.iscoroutinefunction(mock.AsyncMock()))
17261727

17271728
def test_yield_vs_yield_from(self):
17281729
fut = self.new_future(self.loop)

Lib/test/test_inspect.py

+14
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ def test_iscoroutine(self):
188188
gen_coroutine_function_example))))
189189
self.assertTrue(inspect.isgenerator(gen_coro))
190190

191+
self.assertFalse(
192+
inspect.iscoroutinefunction(unittest.mock.Mock()))
193+
self.assertTrue(
194+
inspect.iscoroutinefunction(unittest.mock.AsyncMock()))
191195
self.assertTrue(
192196
inspect.iscoroutinefunction(coroutine_function_example))
193197
self.assertTrue(
@@ -196,6 +200,10 @@ def test_iscoroutine(self):
196200
coroutine_function_example))))
197201
self.assertTrue(inspect.iscoroutine(coro))
198202

203+
self.assertFalse(
204+
inspect.isgeneratorfunction(unittest.mock.Mock()))
205+
self.assertFalse(
206+
inspect.isgeneratorfunction(unittest.mock.AsyncMock()))
199207
self.assertFalse(
200208
inspect.isgeneratorfunction(coroutine_function_example))
201209
self.assertFalse(
@@ -204,6 +212,12 @@ def test_iscoroutine(self):
204212
coroutine_function_example))))
205213
self.assertFalse(inspect.isgenerator(coro))
206214

215+
self.assertFalse(
216+
inspect.isasyncgenfunction(unittest.mock.Mock()))
217+
self.assertFalse(
218+
inspect.isasyncgenfunction(unittest.mock.AsyncMock()))
219+
self.assertFalse(
220+
inspect.isasyncgenfunction(coroutine_function_example))
207221
self.assertTrue(
208222
inspect.isasyncgenfunction(async_generator_function_example))
209223
self.assertTrue(

Lib/unittest/mock.py

+4
Original file line numberDiff line numberDiff line change
@@ -2186,6 +2186,10 @@ def __init__(self, /, *args, **kwargs):
21862186
code_mock = NonCallableMock(spec_set=CodeType)
21872187
code_mock.co_flags = inspect.CO_COROUTINE
21882188
self.__dict__['__code__'] = code_mock
2189+
self.__dict__['__name__'] = 'AsyncMock'
2190+
self.__dict__['__defaults__'] = tuple()
2191+
self.__dict__['__kwdefaults__'] = {}
2192+
self.__dict__['__annotations__'] = None
21892193

21902194
async def _execute_mock_call(self, /, *args, **kwargs):
21912195
# This is nearly just like super(), except for special handling
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`inspect.iscoroutinefunction` now properly returns ``True`` when an instance
2+
of :class:`unittest.mock.AsyncMock` is passed to it. This makes it consistent with
3+
behavior of :func:`asyncio.iscoroutinefunction`. Patch by Mehdi ABAAKOUK.

0 commit comments

Comments
 (0)