commit e3c21a6b3e516af4aef4b66c5beb7fe02e4c84f3 Author: Damian Johnson atagar@torproject.org Date: Sun Aug 9 17:41:36 2020 -0700
Generator methods uncallable when synchronous
Our Synchronous mixin failed to mock any async method that yields because inspect.iscoroutinefunction() does not recognize them...
============================================================
import asyncio import inspect
class Demo(object): async def async_method(self): return 'hi'
async def async_generator(self): yield 'hi'
def print_awaitability(func): print('') print('asyncio.iscoroutinefunction: %s' % asyncio.iscoroutinefunction(func)) print('inspect.iscoroutinefunction: %s' % inspect.iscoroutinefunction(func)) print('inspect.isawaitable: %s' % inspect.isawaitable(func)) print('inspect.isasyncgenfunction: %s' % inspect.isasyncgenfunction(func)) print('')
print('-' * 60) print('Asynchronous method') print('-' * 60)
print_awaitability(Demo.async_method)
print('-' * 60) print('Asynchronous generator') print('-' * 60)
print_awaitability(Demo.async_generator)
============================================================
% python3.7 demo.py ------------------------------------------------------------ Asynchronous method ------------------------------------------------------------
asyncio.iscoroutinefunction: True inspect.iscoroutinefunction: True inspect.isawaitable: False inspect.isasyncgenfunction: False
------------------------------------------------------------ Asynchronous generator ------------------------------------------------------------
asyncio.iscoroutinefunction: False inspect.iscoroutinefunction: False inspect.isawaitable: False inspect.isasyncgenfunction: True --- stem/util/asyncio.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/stem/util/asyncio.py b/stem/util/asyncio.py index 4ee8df3f..e677f13d 100644 --- a/stem/util/asyncio.py +++ b/stem/util/asyncio.py @@ -9,7 +9,6 @@ import asyncio import functools import inspect import threading -import typing import unittest.mock
from types import TracebackType @@ -87,9 +86,9 @@ class Synchronous(object): for name, func in inspect.getmembers(self): if name in ('__aiter__', '__aenter__', '__aexit__'): pass # async object methods with synchronous counterparts - elif isinstance(func, unittest.mock.Mock) and inspect.iscoroutinefunction(func.side_effect): + elif isinstance(func, unittest.mock.Mock) and (inspect.iscoroutinefunction(func.side_effect) or inspect.isasyncgenfunction(func.side_effect)): setattr(self, name, functools.partial(self._run_async_method, name)) - elif inspect.ismethod(func) and inspect.iscoroutinefunction(func): + elif inspect.ismethod(func) and (inspect.iscoroutinefunction(func) or inspect.isasyncgenfunction(func)): setattr(self, name, functools.partial(self._run_async_method, name))
Synchronous.start(self) @@ -216,9 +215,7 @@ class Synchronous(object): if self._loop is None: Synchronous.start(self)
- # convert iterator if indicated by this method's name or type hint - - if method_name == '__aiter__' or (inspect.ismethod(func) and typing.get_type_hints(func).get('return') == AsyncIterator): + if inspect.isasyncgenfunction(func): async def convert_generator(generator: AsyncIterator) -> Iterator: return iter([d async for d in generator])
tor-commits@lists.torproject.org