diff --git a/uvloop/chain_futs.pyx b/uvloop/chain_futs.pyx index 9fdc3b2..725522a 100644 --- a/uvloop/chain_futs.pyx +++ b/uvloop/chain_futs.pyx @@ -45,9 +45,9 @@ cdef _chain_future(source, destination): If destination is cancelled, source gets cancelled too. Compatible with both asyncio.Future and concurrent.futures.Future. """ - if not isinstance(source, (aio_Future, cc_Future)): + if not isfuture(source) and not isinstance(source, cc_Future): raise TypeError('A future is required for source argument') - if not isinstance(destination, (aio_Future, cc_Future)): + if not isfuture(destination) and not isinstance(destination, cc_Future): raise TypeError('A future is required for destination argument') source_loop = None @@ -58,18 +58,16 @@ cdef _chain_future(source, destination): if source_type is uvloop_Future: source_loop = (source)._loop - elif source_type is not cc_Future and \ - isinstance(source, aio_Future): + elif source_type is not cc_Future and isfuture(source): source_loop = source._loop if dest_type is uvloop_Future: dest_loop = (destination)._loop - elif dest_type is not cc_Future and \ - isinstance(destination, aio_Future): + elif dest_type is not cc_Future and isfuture(destination): dest_loop = destination._loop def _set_state(future, other): - if isinstance(future, aio_Future): + if isfuture(future): _copy_future_state(other, future) else: _set_concurrent_future_state(future, other) @@ -95,7 +93,7 @@ def _wrap_future(future, *, loop=None): # Don't use this function -- it's here for tests purposes only # and can be removed in future versions of uvloop. - if isinstance(future, aio_Future): + if isfuture(future): return future assert isinstance(future, cc_Future), \ 'concurrent.futures.Future is expected, got {!r}'.format(future) diff --git a/uvloop/handles/basetransport.pyx b/uvloop/handles/basetransport.pyx index b9245fe..b339a7e 100644 --- a/uvloop/handles/basetransport.pyx +++ b/uvloop/handles/basetransport.pyx @@ -200,7 +200,7 @@ cdef class UVBaseTransport(UVSocketHandle): (server)._attach() cdef inline _set_waiter(self, object waiter): - if waiter is not None and not isinstance(waiter, aio_Future): + if waiter is not None and not isfuture(waiter): raise TypeError( 'invalid waiter object {!r}, expected asyncio.Future'. format(waiter)) diff --git a/uvloop/includes/stdlib.pxi b/uvloop/includes/stdlib.pxi index 35f9e9c..bc2ab27 100644 --- a/uvloop/includes/stdlib.pxi +++ b/uvloop/includes/stdlib.pxi @@ -37,6 +37,7 @@ cdef aio_BaseProtocol = asyncio.BaseProtocol cdef aio_Protocol = asyncio.Protocol cdef aio_SSLProtocol = asyncio.sslproto.SSLProtocol cdef aio_debug_wrapper = asyncio.coroutines.debug_wrapper +cdef aio_isfuture = getattr(asyncio, 'isfuture', None) cdef col_deque = collections.deque cdef col_Iterable = collections.Iterable diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index d631c87..ed31c1f 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -40,6 +40,13 @@ include "includes/stdlib.pxi" include "errors.pyx" +cdef isfuture(obj): + if aio_isfuture is None: + return isinstance(obj, aio_Future) + else: + return getattr(obj, '_asyncio_future_blocking', None) is not None + + @cython.no_gc_clear cdef class Loop: def __cinit__(self): @@ -1115,7 +1122,7 @@ cdef class Loop: """ self._check_closed() - new_task = not isinstance(future, aio_Future) + new_task = not isfuture(future) future = aio_ensure_future(future, loop=self) if new_task: # An exception is raised if the future didn't complete, so there diff --git a/uvloop/task.pyx b/uvloop/task.pyx index ff2e218..30a14c0 100644 --- a/uvloop/task.pyx +++ b/uvloop/task.pyx @@ -152,7 +152,7 @@ cdef class BaseTask(BaseFuture): else: self._raise_yield(result) - elif result_type is aio_Future or isinstance(result, aio_Future): + elif result_type is aio_Future or isfuture(result): # Yielded Future must come from Future.__iter__(). if result._loop is not self._loop: self._raise_wrong_loop(result)