Skip to content

Commit 525cca2

Browse files
committed
Copy futures._chain_future implementation (unbreaks Python 3.5.0)
1 parent 0a321de commit 525cca2

File tree

3 files changed

+91
-3
lines changed

3 files changed

+91
-3
lines changed

uvloop/chain_futs.pyx

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Copied from asyncio 3.5.2
2+
3+
cdef _set_concurrent_future_state(concurrent, source):
4+
"""Copy state from a future to a concurrent.futures.Future."""
5+
assert source.done()
6+
if source.cancelled():
7+
concurrent.cancel()
8+
if not concurrent.set_running_or_notify_cancel():
9+
return
10+
exception = source.exception()
11+
if exception is not None:
12+
concurrent.set_exception(exception)
13+
else:
14+
result = source.result()
15+
concurrent.set_result(result)
16+
17+
18+
cdef _copy_future_state(source, dest):
19+
"""Internal helper to copy state from another Future.
20+
21+
The other Future may be a concurrent.futures.Future.
22+
"""
23+
assert source.done()
24+
if dest.cancelled():
25+
return
26+
assert not dest.done()
27+
if source.cancelled():
28+
dest.cancel()
29+
else:
30+
exception = source.exception()
31+
if exception is not None:
32+
dest.set_exception(exception)
33+
else:
34+
result = source.result()
35+
dest.set_result(result)
36+
37+
38+
cdef _chain_future(source, destination):
39+
"""Chain two futures so that when one completes, so does the other.
40+
41+
The result (or exception) of source will be copied to destination.
42+
If destination is cancelled, source gets cancelled too.
43+
Compatible with both asyncio.Future and concurrent.futures.Future.
44+
"""
45+
if not isinstance(source, (aio_Future, cc_Future)):
46+
raise TypeError('A future is required for source argument')
47+
if not isinstance(destination, (aio_Future, cc_Future)):
48+
raise TypeError('A future is required for destination argument')
49+
50+
source_loop = None
51+
dest_loop = None
52+
53+
source_type = type(source)
54+
dest_type = type(destination)
55+
56+
if source_type is uvloop_Future:
57+
source_loop = (<BaseFuture>source)._loop
58+
elif source_type is not cc_Future and \
59+
isinstance(source, aio_Future):
60+
source_loop = source._loop
61+
62+
if dest_type is uvloop_Future:
63+
dest_loop = (<BaseFuture>destination)._loop
64+
elif dest_type is not cc_Future and \
65+
isinstance(destination, aio_Future):
66+
dest_loop = destination._loop
67+
68+
def _set_state(future, other):
69+
if isinstance(future, aio_Future):
70+
_copy_future_state(other, future)
71+
else:
72+
_set_concurrent_future_state(future, other)
73+
74+
def _call_check_cancel(destination):
75+
if destination.cancelled():
76+
if source_loop is None or source_loop is dest_loop:
77+
source.cancel()
78+
else:
79+
source_loop.call_soon_threadsafe(source.cancel)
80+
81+
def _call_set_state(source):
82+
if dest_loop is None or dest_loop is source_loop:
83+
_set_state(destination, source)
84+
else:
85+
dest_loop.call_soon_threadsafe(_set_state, destination, source)
86+
87+
destination.add_done_callback(_call_check_cancel)
88+
source.add_done_callback(_call_set_state)

uvloop/includes/stdlib.pxi

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import time
1818
import warnings
1919

2020

21-
cdef aio_chain_future = asyncio.futures._chain_future
2221
cdef aio_get_event_loop = asyncio.get_event_loop
2322
cdef aio_CancelledError = asyncio.CancelledError
2423
cdef aio_InvalidStateError = asyncio.InvalidStateError
@@ -32,7 +31,6 @@ cdef aio_logger = asyncio.log.logger
3231
cdef aio__check_resolved_address = asyncio.base_events._check_resolved_address
3332
cdef aio_iscoroutine = asyncio.iscoroutine
3433
cdef aio_iscoroutinefunction = asyncio.iscoroutinefunction
35-
cdef aio_wrap_future = asyncio.wrap_future
3634
cdef aio_BaseProtocol = asyncio.BaseProtocol
3735
cdef aio_Protocol = asyncio.Protocol
3836
cdef aio_SSLProtocol = asyncio.sslproto.SSLProtocol
@@ -43,6 +41,7 @@ cdef col_Iterable = collections.Iterable
4341
cdef col_Counter = collections.Counter
4442

4543
cdef cc_ThreadPoolExecutor = concurrent.futures.ThreadPoolExecutor
44+
cdef cc_Future = concurrent.futures.Future
4645

4746
cdef ft_partial = functools.partial
4847

uvloop/loop.pyx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1837,7 +1837,7 @@ cdef class Loop:
18371837
self._default_executor = executor
18381838

18391839
new_fut = self._new_future()
1840-
aio_chain_future(executor.submit(func, *args), new_fut)
1840+
_chain_future(executor.submit(func, *args), new_fut)
18411841
return new_fut
18421842

18431843
def set_default_executor(self, executor):
@@ -2263,6 +2263,7 @@ include "server.pyx"
22632263
include "os_signal.pyx"
22642264

22652265
include "future.pyx"
2266+
include "chain_futs.pyx"
22662267
include "task.pyx"
22672268

22682269

0 commit comments

Comments
 (0)