Karthikeyan Singaravelan <tir.kar...@gmail.com> added the comment:

> BUT I think removing the `if getattr(obj, '__code__', None)` from 
> `_is_async_obj` actually makes this work correctly. It is possible for a 
> coroutine object to not have a __code__, but I don't think it is possible for 
> a coroutine function to be missing a __code__. 

Sorry, I am little confused here. If the code attribute check is removed then 
my test case in PR fails since obj.__code__ that is passed through 
iscoroutinefunction returns True. Maybe something along the lines of below that 
if there is a __code__ attribute then always check it's of CodeType. So that my 
test passes with MagicMock.__code__ detected.

If I understand the awaitable examples correctly, mocking the obj which is an 
Awaitable should be returning an AsyncMock. But obj doesn't contain __code__ 
and hence check for inspect.isawaitable is never done causing 
_is_async_obj(obj) to return False and subsequently it's patched with MagicMock.


from collections.abc import Awaitable
from unittest.mock import patch

class NewCoroutine(Awaitable):
    def __await__():
        pass

obj = NewCoroutine()

with patch(f"{__name__}.obj") as m:
    print(m)

$ ./python.exe ../backups/bpo37251_awaitable.py
<MagicMock name='obj' id='4552158896'>

On removing the __code__ attribute check my test case of MagicMock with 
__code__ passes through iscoroutinefunction. Perhaps an acceptable tradeoff 
would be to check for __code__ and if present to be a CodeType or else to 
resume normal check like below. This way an AsyncMock is returned. Also there 
is no test failure. I have less understanding on asyncio terminologies over 
coroutine and awaitables so feel free to correct me if I am wrong. I guess it 
would be also helpful to have good number of tests for different asyncio object 
cases so that this could also be documented.

$ ./python.exe ../backups/bpo37251_awaitable.py
<AsyncMock name='obj' id='4363294672'>

# _is_async_obj to check for __code__ to be CodeType only if present.

def _is_async_obj(obj):
    code = getattr(obj, '__code__', None)
    if code and not isinstance(code, CodeType):
        return False
    return asyncio.iscoroutinefunction(obj) or inspect.isawaitable(obj)

# Also verified asyncio.sleep() to return True for _is_async_obj with above 
definition

>>> from unittest.mock import _is_async_func, _is_async_obj
>>> import asyncio
>>> _is_async_obj(asyncio.sleep(1))
<stdin>:1: RuntimeWarning: coroutine 'sleep' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
True

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue37251>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to