[tor-commits] [stem/master] Generator methods uncallable when synchronous

atagar at torproject.org atagar at torproject.org
Wed Aug 12 00:06:19 UTC 2020


commit e3c21a6b3e516af4aef4b66c5beb7fe02e4c84f3
Author: Damian Johnson <atagar at 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])
 





More information about the tor-commits mailing list