Skip to content

Commit 4261b6b

Browse files
silehtambv
andauthored
pythongh-84753: Make inspect.iscoroutinefunction() work with AsyncMock (python#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@langa.pl>
1 parent 639e351 commit 4261b6b

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
@@ -395,7 +395,7 @@ def _has_code_flag(f, flag):
395395
while ismethod(f):
396396
f = f.__func__
397397
f = functools._unwrap_partial(f)
398-
if not isfunction(f):
398+
if not (isfunction(f) or _signature_is_functionlike(f)):
399399
return False
400400
return bool(f.__code__.co_flags & flag)
401401

Lib/test/test_asyncio/test_tasks.py

+1
Original file line numberDiff line numberDiff line change
@@ -1649,6 +1649,7 @@ async def fn2():
16491649
self.assertTrue(asyncio.iscoroutinefunction(fn2))
16501650

16511651
self.assertFalse(asyncio.iscoroutinefunction(mock.Mock()))
1652+
self.assertTrue(asyncio.iscoroutinefunction(mock.AsyncMock()))
16521653

16531654
def test_coroutine_non_gen_function(self):
16541655
async def func():

Lib/test/test_inspect.py

+14
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ def test_iscoroutine(self):
202202
gen_coroutine_function_example))))
203203
self.assertTrue(inspect.isgenerator(gen_coro))
204204

205+
self.assertFalse(
206+
inspect.iscoroutinefunction(unittest.mock.Mock()))
207+
self.assertTrue(
208+
inspect.iscoroutinefunction(unittest.mock.AsyncMock()))
205209
self.assertTrue(
206210
inspect.iscoroutinefunction(coroutine_function_example))
207211
self.assertTrue(
@@ -210,6 +214,10 @@ def test_iscoroutine(self):
210214
coroutine_function_example))))
211215
self.assertTrue(inspect.iscoroutine(coro))
212216

217+
self.assertFalse(
218+
inspect.isgeneratorfunction(unittest.mock.Mock()))
219+
self.assertFalse(
220+
inspect.isgeneratorfunction(unittest.mock.AsyncMock()))
213221
self.assertFalse(
214222
inspect.isgeneratorfunction(coroutine_function_example))
215223
self.assertFalse(
@@ -218,6 +226,12 @@ def test_iscoroutine(self):
218226
coroutine_function_example))))
219227
self.assertFalse(inspect.isgenerator(coro))
220228

229+
self.assertFalse(
230+
inspect.isasyncgenfunction(unittest.mock.Mock()))
231+
self.assertFalse(
232+
inspect.isasyncgenfunction(unittest.mock.AsyncMock()))
233+
self.assertFalse(
234+
inspect.isasyncgenfunction(coroutine_function_example))
221235
self.assertTrue(
222236
inspect.isasyncgenfunction(async_generator_function_example))
223237
self.assertTrue(

Lib/unittest/mock.py

+4
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,10 @@ def __init__(self, /, *args, **kwargs):
21752175
code_mock = NonCallableMock(spec_set=CodeType)
21762176
code_mock.co_flags = inspect.CO_COROUTINE
21772177
self.__dict__['__code__'] = code_mock
2178+
self.__dict__['__name__'] = 'AsyncMock'
2179+
self.__dict__['__defaults__'] = tuple()
2180+
self.__dict__['__kwdefaults__'] = {}
2181+
self.__dict__['__annotations__'] = None
21782182

21792183
async def _execute_mock_call(self, /, *args, **kwargs):
21802184
# 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)