xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/asyncio/futures.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""A Future class similar to the one in PEP 3148."""
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Worker__all__ = (
4*cda5da8dSAndroid Build Coastguard Worker    'Future', 'wrap_future', 'isfuture',
5*cda5da8dSAndroid Build Coastguard Worker)
6*cda5da8dSAndroid Build Coastguard Worker
7*cda5da8dSAndroid Build Coastguard Workerimport concurrent.futures
8*cda5da8dSAndroid Build Coastguard Workerimport contextvars
9*cda5da8dSAndroid Build Coastguard Workerimport logging
10*cda5da8dSAndroid Build Coastguard Workerimport sys
11*cda5da8dSAndroid Build Coastguard Workerfrom types import GenericAlias
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard Workerfrom . import base_futures
14*cda5da8dSAndroid Build Coastguard Workerfrom . import events
15*cda5da8dSAndroid Build Coastguard Workerfrom . import exceptions
16*cda5da8dSAndroid Build Coastguard Workerfrom . import format_helpers
17*cda5da8dSAndroid Build Coastguard Worker
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard Workerisfuture = base_futures.isfuture
20*cda5da8dSAndroid Build Coastguard Worker
21*cda5da8dSAndroid Build Coastguard Worker
22*cda5da8dSAndroid Build Coastguard Worker_PENDING = base_futures._PENDING
23*cda5da8dSAndroid Build Coastguard Worker_CANCELLED = base_futures._CANCELLED
24*cda5da8dSAndroid Build Coastguard Worker_FINISHED = base_futures._FINISHED
25*cda5da8dSAndroid Build Coastguard Worker
26*cda5da8dSAndroid Build Coastguard Worker
27*cda5da8dSAndroid Build Coastguard WorkerSTACK_DEBUG = logging.DEBUG - 1  # heavy-duty debugging
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard Worker
30*cda5da8dSAndroid Build Coastguard Workerclass Future:
31*cda5da8dSAndroid Build Coastguard Worker    """This class is *almost* compatible with concurrent.futures.Future.
32*cda5da8dSAndroid Build Coastguard Worker
33*cda5da8dSAndroid Build Coastguard Worker    Differences:
34*cda5da8dSAndroid Build Coastguard Worker
35*cda5da8dSAndroid Build Coastguard Worker    - This class is not thread-safe.
36*cda5da8dSAndroid Build Coastguard Worker
37*cda5da8dSAndroid Build Coastguard Worker    - result() and exception() do not take a timeout argument and
38*cda5da8dSAndroid Build Coastguard Worker      raise an exception when the future isn't done yet.
39*cda5da8dSAndroid Build Coastguard Worker
40*cda5da8dSAndroid Build Coastguard Worker    - Callbacks registered with add_done_callback() are always called
41*cda5da8dSAndroid Build Coastguard Worker      via the event loop's call_soon().
42*cda5da8dSAndroid Build Coastguard Worker
43*cda5da8dSAndroid Build Coastguard Worker    - This class is not compatible with the wait() and as_completed()
44*cda5da8dSAndroid Build Coastguard Worker      methods in the concurrent.futures package.
45*cda5da8dSAndroid Build Coastguard Worker
46*cda5da8dSAndroid Build Coastguard Worker    (In Python 3.4 or later we may be able to unify the implementations.)
47*cda5da8dSAndroid Build Coastguard Worker    """
48*cda5da8dSAndroid Build Coastguard Worker
49*cda5da8dSAndroid Build Coastguard Worker    # Class variables serving as defaults for instance variables.
50*cda5da8dSAndroid Build Coastguard Worker    _state = _PENDING
51*cda5da8dSAndroid Build Coastguard Worker    _result = None
52*cda5da8dSAndroid Build Coastguard Worker    _exception = None
53*cda5da8dSAndroid Build Coastguard Worker    _loop = None
54*cda5da8dSAndroid Build Coastguard Worker    _source_traceback = None
55*cda5da8dSAndroid Build Coastguard Worker    _cancel_message = None
56*cda5da8dSAndroid Build Coastguard Worker    # A saved CancelledError for later chaining as an exception context.
57*cda5da8dSAndroid Build Coastguard Worker    _cancelled_exc = None
58*cda5da8dSAndroid Build Coastguard Worker
59*cda5da8dSAndroid Build Coastguard Worker    # This field is used for a dual purpose:
60*cda5da8dSAndroid Build Coastguard Worker    # - Its presence is a marker to declare that a class implements
61*cda5da8dSAndroid Build Coastguard Worker    #   the Future protocol (i.e. is intended to be duck-type compatible).
62*cda5da8dSAndroid Build Coastguard Worker    #   The value must also be not-None, to enable a subclass to declare
63*cda5da8dSAndroid Build Coastguard Worker    #   that it is not compatible by setting this to None.
64*cda5da8dSAndroid Build Coastguard Worker    # - It is set by __iter__() below so that Task._step() can tell
65*cda5da8dSAndroid Build Coastguard Worker    #   the difference between
66*cda5da8dSAndroid Build Coastguard Worker    #   `await Future()` or`yield from Future()` (correct) vs.
67*cda5da8dSAndroid Build Coastguard Worker    #   `yield Future()` (incorrect).
68*cda5da8dSAndroid Build Coastguard Worker    _asyncio_future_blocking = False
69*cda5da8dSAndroid Build Coastguard Worker
70*cda5da8dSAndroid Build Coastguard Worker    __log_traceback = False
71*cda5da8dSAndroid Build Coastguard Worker
72*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, *, loop=None):
73*cda5da8dSAndroid Build Coastguard Worker        """Initialize the future.
74*cda5da8dSAndroid Build Coastguard Worker
75*cda5da8dSAndroid Build Coastguard Worker        The optional event_loop argument allows explicitly setting the event
76*cda5da8dSAndroid Build Coastguard Worker        loop object used by the future. If it's not provided, the future uses
77*cda5da8dSAndroid Build Coastguard Worker        the default event loop.
78*cda5da8dSAndroid Build Coastguard Worker        """
79*cda5da8dSAndroid Build Coastguard Worker        if loop is None:
80*cda5da8dSAndroid Build Coastguard Worker            self._loop = events._get_event_loop()
81*cda5da8dSAndroid Build Coastguard Worker        else:
82*cda5da8dSAndroid Build Coastguard Worker            self._loop = loop
83*cda5da8dSAndroid Build Coastguard Worker        self._callbacks = []
84*cda5da8dSAndroid Build Coastguard Worker        if self._loop.get_debug():
85*cda5da8dSAndroid Build Coastguard Worker            self._source_traceback = format_helpers.extract_stack(
86*cda5da8dSAndroid Build Coastguard Worker                sys._getframe(1))
87*cda5da8dSAndroid Build Coastguard Worker
88*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
89*cda5da8dSAndroid Build Coastguard Worker        return base_futures._future_repr(self)
90*cda5da8dSAndroid Build Coastguard Worker
91*cda5da8dSAndroid Build Coastguard Worker    def __del__(self):
92*cda5da8dSAndroid Build Coastguard Worker        if not self.__log_traceback:
93*cda5da8dSAndroid Build Coastguard Worker            # set_exception() was not called, or result() or exception()
94*cda5da8dSAndroid Build Coastguard Worker            # has consumed the exception
95*cda5da8dSAndroid Build Coastguard Worker            return
96*cda5da8dSAndroid Build Coastguard Worker        exc = self._exception
97*cda5da8dSAndroid Build Coastguard Worker        context = {
98*cda5da8dSAndroid Build Coastguard Worker            'message':
99*cda5da8dSAndroid Build Coastguard Worker                f'{self.__class__.__name__} exception was never retrieved',
100*cda5da8dSAndroid Build Coastguard Worker            'exception': exc,
101*cda5da8dSAndroid Build Coastguard Worker            'future': self,
102*cda5da8dSAndroid Build Coastguard Worker        }
103*cda5da8dSAndroid Build Coastguard Worker        if self._source_traceback:
104*cda5da8dSAndroid Build Coastguard Worker            context['source_traceback'] = self._source_traceback
105*cda5da8dSAndroid Build Coastguard Worker        self._loop.call_exception_handler(context)
106*cda5da8dSAndroid Build Coastguard Worker
107*cda5da8dSAndroid Build Coastguard Worker    __class_getitem__ = classmethod(GenericAlias)
108*cda5da8dSAndroid Build Coastguard Worker
109*cda5da8dSAndroid Build Coastguard Worker    @property
110*cda5da8dSAndroid Build Coastguard Worker    def _log_traceback(self):
111*cda5da8dSAndroid Build Coastguard Worker        return self.__log_traceback
112*cda5da8dSAndroid Build Coastguard Worker
113*cda5da8dSAndroid Build Coastguard Worker    @_log_traceback.setter
114*cda5da8dSAndroid Build Coastguard Worker    def _log_traceback(self, val):
115*cda5da8dSAndroid Build Coastguard Worker        if val:
116*cda5da8dSAndroid Build Coastguard Worker            raise ValueError('_log_traceback can only be set to False')
117*cda5da8dSAndroid Build Coastguard Worker        self.__log_traceback = False
118*cda5da8dSAndroid Build Coastguard Worker
119*cda5da8dSAndroid Build Coastguard Worker    def get_loop(self):
120*cda5da8dSAndroid Build Coastguard Worker        """Return the event loop the Future is bound to."""
121*cda5da8dSAndroid Build Coastguard Worker        loop = self._loop
122*cda5da8dSAndroid Build Coastguard Worker        if loop is None:
123*cda5da8dSAndroid Build Coastguard Worker            raise RuntimeError("Future object is not initialized.")
124*cda5da8dSAndroid Build Coastguard Worker        return loop
125*cda5da8dSAndroid Build Coastguard Worker
126*cda5da8dSAndroid Build Coastguard Worker    def _make_cancelled_error(self):
127*cda5da8dSAndroid Build Coastguard Worker        """Create the CancelledError to raise if the Future is cancelled.
128*cda5da8dSAndroid Build Coastguard Worker
129*cda5da8dSAndroid Build Coastguard Worker        This should only be called once when handling a cancellation since
130*cda5da8dSAndroid Build Coastguard Worker        it erases the saved context exception value.
131*cda5da8dSAndroid Build Coastguard Worker        """
132*cda5da8dSAndroid Build Coastguard Worker        if self._cancelled_exc is not None:
133*cda5da8dSAndroid Build Coastguard Worker            exc = self._cancelled_exc
134*cda5da8dSAndroid Build Coastguard Worker            self._cancelled_exc = None
135*cda5da8dSAndroid Build Coastguard Worker            return exc
136*cda5da8dSAndroid Build Coastguard Worker
137*cda5da8dSAndroid Build Coastguard Worker        if self._cancel_message is None:
138*cda5da8dSAndroid Build Coastguard Worker            exc = exceptions.CancelledError()
139*cda5da8dSAndroid Build Coastguard Worker        else:
140*cda5da8dSAndroid Build Coastguard Worker            exc = exceptions.CancelledError(self._cancel_message)
141*cda5da8dSAndroid Build Coastguard Worker        exc.__context__ = self._cancelled_exc
142*cda5da8dSAndroid Build Coastguard Worker        # Remove the reference since we don't need this anymore.
143*cda5da8dSAndroid Build Coastguard Worker        self._cancelled_exc = None
144*cda5da8dSAndroid Build Coastguard Worker        return exc
145*cda5da8dSAndroid Build Coastguard Worker
146*cda5da8dSAndroid Build Coastguard Worker    def cancel(self, msg=None):
147*cda5da8dSAndroid Build Coastguard Worker        """Cancel the future and schedule callbacks.
148*cda5da8dSAndroid Build Coastguard Worker
149*cda5da8dSAndroid Build Coastguard Worker        If the future is already done or cancelled, return False.  Otherwise,
150*cda5da8dSAndroid Build Coastguard Worker        change the future's state to cancelled, schedule the callbacks and
151*cda5da8dSAndroid Build Coastguard Worker        return True.
152*cda5da8dSAndroid Build Coastguard Worker        """
153*cda5da8dSAndroid Build Coastguard Worker        self.__log_traceback = False
154*cda5da8dSAndroid Build Coastguard Worker        if self._state != _PENDING:
155*cda5da8dSAndroid Build Coastguard Worker            return False
156*cda5da8dSAndroid Build Coastguard Worker        self._state = _CANCELLED
157*cda5da8dSAndroid Build Coastguard Worker        self._cancel_message = msg
158*cda5da8dSAndroid Build Coastguard Worker        self.__schedule_callbacks()
159*cda5da8dSAndroid Build Coastguard Worker        return True
160*cda5da8dSAndroid Build Coastguard Worker
161*cda5da8dSAndroid Build Coastguard Worker    def __schedule_callbacks(self):
162*cda5da8dSAndroid Build Coastguard Worker        """Internal: Ask the event loop to call all callbacks.
163*cda5da8dSAndroid Build Coastguard Worker
164*cda5da8dSAndroid Build Coastguard Worker        The callbacks are scheduled to be called as soon as possible. Also
165*cda5da8dSAndroid Build Coastguard Worker        clears the callback list.
166*cda5da8dSAndroid Build Coastguard Worker        """
167*cda5da8dSAndroid Build Coastguard Worker        callbacks = self._callbacks[:]
168*cda5da8dSAndroid Build Coastguard Worker        if not callbacks:
169*cda5da8dSAndroid Build Coastguard Worker            return
170*cda5da8dSAndroid Build Coastguard Worker
171*cda5da8dSAndroid Build Coastguard Worker        self._callbacks[:] = []
172*cda5da8dSAndroid Build Coastguard Worker        for callback, ctx in callbacks:
173*cda5da8dSAndroid Build Coastguard Worker            self._loop.call_soon(callback, self, context=ctx)
174*cda5da8dSAndroid Build Coastguard Worker
175*cda5da8dSAndroid Build Coastguard Worker    def cancelled(self):
176*cda5da8dSAndroid Build Coastguard Worker        """Return True if the future was cancelled."""
177*cda5da8dSAndroid Build Coastguard Worker        return self._state == _CANCELLED
178*cda5da8dSAndroid Build Coastguard Worker
179*cda5da8dSAndroid Build Coastguard Worker    # Don't implement running(); see http://bugs.python.org/issue18699
180*cda5da8dSAndroid Build Coastguard Worker
181*cda5da8dSAndroid Build Coastguard Worker    def done(self):
182*cda5da8dSAndroid Build Coastguard Worker        """Return True if the future is done.
183*cda5da8dSAndroid Build Coastguard Worker
184*cda5da8dSAndroid Build Coastguard Worker        Done means either that a result / exception are available, or that the
185*cda5da8dSAndroid Build Coastguard Worker        future was cancelled.
186*cda5da8dSAndroid Build Coastguard Worker        """
187*cda5da8dSAndroid Build Coastguard Worker        return self._state != _PENDING
188*cda5da8dSAndroid Build Coastguard Worker
189*cda5da8dSAndroid Build Coastguard Worker    def result(self):
190*cda5da8dSAndroid Build Coastguard Worker        """Return the result this future represents.
191*cda5da8dSAndroid Build Coastguard Worker
192*cda5da8dSAndroid Build Coastguard Worker        If the future has been cancelled, raises CancelledError.  If the
193*cda5da8dSAndroid Build Coastguard Worker        future's result isn't yet available, raises InvalidStateError.  If
194*cda5da8dSAndroid Build Coastguard Worker        the future is done and has an exception set, this exception is raised.
195*cda5da8dSAndroid Build Coastguard Worker        """
196*cda5da8dSAndroid Build Coastguard Worker        if self._state == _CANCELLED:
197*cda5da8dSAndroid Build Coastguard Worker            exc = self._make_cancelled_error()
198*cda5da8dSAndroid Build Coastguard Worker            raise exc
199*cda5da8dSAndroid Build Coastguard Worker        if self._state != _FINISHED:
200*cda5da8dSAndroid Build Coastguard Worker            raise exceptions.InvalidStateError('Result is not ready.')
201*cda5da8dSAndroid Build Coastguard Worker        self.__log_traceback = False
202*cda5da8dSAndroid Build Coastguard Worker        if self._exception is not None:
203*cda5da8dSAndroid Build Coastguard Worker            raise self._exception.with_traceback(self._exception_tb)
204*cda5da8dSAndroid Build Coastguard Worker        return self._result
205*cda5da8dSAndroid Build Coastguard Worker
206*cda5da8dSAndroid Build Coastguard Worker    def exception(self):
207*cda5da8dSAndroid Build Coastguard Worker        """Return the exception that was set on this future.
208*cda5da8dSAndroid Build Coastguard Worker
209*cda5da8dSAndroid Build Coastguard Worker        The exception (or None if no exception was set) is returned only if
210*cda5da8dSAndroid Build Coastguard Worker        the future is done.  If the future has been cancelled, raises
211*cda5da8dSAndroid Build Coastguard Worker        CancelledError.  If the future isn't done yet, raises
212*cda5da8dSAndroid Build Coastguard Worker        InvalidStateError.
213*cda5da8dSAndroid Build Coastguard Worker        """
214*cda5da8dSAndroid Build Coastguard Worker        if self._state == _CANCELLED:
215*cda5da8dSAndroid Build Coastguard Worker            exc = self._make_cancelled_error()
216*cda5da8dSAndroid Build Coastguard Worker            raise exc
217*cda5da8dSAndroid Build Coastguard Worker        if self._state != _FINISHED:
218*cda5da8dSAndroid Build Coastguard Worker            raise exceptions.InvalidStateError('Exception is not set.')
219*cda5da8dSAndroid Build Coastguard Worker        self.__log_traceback = False
220*cda5da8dSAndroid Build Coastguard Worker        return self._exception
221*cda5da8dSAndroid Build Coastguard Worker
222*cda5da8dSAndroid Build Coastguard Worker    def add_done_callback(self, fn, *, context=None):
223*cda5da8dSAndroid Build Coastguard Worker        """Add a callback to be run when the future becomes done.
224*cda5da8dSAndroid Build Coastguard Worker
225*cda5da8dSAndroid Build Coastguard Worker        The callback is called with a single argument - the future object. If
226*cda5da8dSAndroid Build Coastguard Worker        the future is already done when this is called, the callback is
227*cda5da8dSAndroid Build Coastguard Worker        scheduled with call_soon.
228*cda5da8dSAndroid Build Coastguard Worker        """
229*cda5da8dSAndroid Build Coastguard Worker        if self._state != _PENDING:
230*cda5da8dSAndroid Build Coastguard Worker            self._loop.call_soon(fn, self, context=context)
231*cda5da8dSAndroid Build Coastguard Worker        else:
232*cda5da8dSAndroid Build Coastguard Worker            if context is None:
233*cda5da8dSAndroid Build Coastguard Worker                context = contextvars.copy_context()
234*cda5da8dSAndroid Build Coastguard Worker            self._callbacks.append((fn, context))
235*cda5da8dSAndroid Build Coastguard Worker
236*cda5da8dSAndroid Build Coastguard Worker    # New method not in PEP 3148.
237*cda5da8dSAndroid Build Coastguard Worker
238*cda5da8dSAndroid Build Coastguard Worker    def remove_done_callback(self, fn):
239*cda5da8dSAndroid Build Coastguard Worker        """Remove all instances of a callback from the "call when done" list.
240*cda5da8dSAndroid Build Coastguard Worker
241*cda5da8dSAndroid Build Coastguard Worker        Returns the number of callbacks removed.
242*cda5da8dSAndroid Build Coastguard Worker        """
243*cda5da8dSAndroid Build Coastguard Worker        filtered_callbacks = [(f, ctx)
244*cda5da8dSAndroid Build Coastguard Worker                              for (f, ctx) in self._callbacks
245*cda5da8dSAndroid Build Coastguard Worker                              if f != fn]
246*cda5da8dSAndroid Build Coastguard Worker        removed_count = len(self._callbacks) - len(filtered_callbacks)
247*cda5da8dSAndroid Build Coastguard Worker        if removed_count:
248*cda5da8dSAndroid Build Coastguard Worker            self._callbacks[:] = filtered_callbacks
249*cda5da8dSAndroid Build Coastguard Worker        return removed_count
250*cda5da8dSAndroid Build Coastguard Worker
251*cda5da8dSAndroid Build Coastguard Worker    # So-called internal methods (note: no set_running_or_notify_cancel()).
252*cda5da8dSAndroid Build Coastguard Worker
253*cda5da8dSAndroid Build Coastguard Worker    def set_result(self, result):
254*cda5da8dSAndroid Build Coastguard Worker        """Mark the future done and set its result.
255*cda5da8dSAndroid Build Coastguard Worker
256*cda5da8dSAndroid Build Coastguard Worker        If the future is already done when this method is called, raises
257*cda5da8dSAndroid Build Coastguard Worker        InvalidStateError.
258*cda5da8dSAndroid Build Coastguard Worker        """
259*cda5da8dSAndroid Build Coastguard Worker        if self._state != _PENDING:
260*cda5da8dSAndroid Build Coastguard Worker            raise exceptions.InvalidStateError(f'{self._state}: {self!r}')
261*cda5da8dSAndroid Build Coastguard Worker        self._result = result
262*cda5da8dSAndroid Build Coastguard Worker        self._state = _FINISHED
263*cda5da8dSAndroid Build Coastguard Worker        self.__schedule_callbacks()
264*cda5da8dSAndroid Build Coastguard Worker
265*cda5da8dSAndroid Build Coastguard Worker    def set_exception(self, exception):
266*cda5da8dSAndroid Build Coastguard Worker        """Mark the future done and set an exception.
267*cda5da8dSAndroid Build Coastguard Worker
268*cda5da8dSAndroid Build Coastguard Worker        If the future is already done when this method is called, raises
269*cda5da8dSAndroid Build Coastguard Worker        InvalidStateError.
270*cda5da8dSAndroid Build Coastguard Worker        """
271*cda5da8dSAndroid Build Coastguard Worker        if self._state != _PENDING:
272*cda5da8dSAndroid Build Coastguard Worker            raise exceptions.InvalidStateError(f'{self._state}: {self!r}')
273*cda5da8dSAndroid Build Coastguard Worker        if isinstance(exception, type):
274*cda5da8dSAndroid Build Coastguard Worker            exception = exception()
275*cda5da8dSAndroid Build Coastguard Worker        if type(exception) is StopIteration:
276*cda5da8dSAndroid Build Coastguard Worker            raise TypeError("StopIteration interacts badly with generators "
277*cda5da8dSAndroid Build Coastguard Worker                            "and cannot be raised into a Future")
278*cda5da8dSAndroid Build Coastguard Worker        self._exception = exception
279*cda5da8dSAndroid Build Coastguard Worker        self._exception_tb = exception.__traceback__
280*cda5da8dSAndroid Build Coastguard Worker        self._state = _FINISHED
281*cda5da8dSAndroid Build Coastguard Worker        self.__schedule_callbacks()
282*cda5da8dSAndroid Build Coastguard Worker        self.__log_traceback = True
283*cda5da8dSAndroid Build Coastguard Worker
284*cda5da8dSAndroid Build Coastguard Worker    def __await__(self):
285*cda5da8dSAndroid Build Coastguard Worker        if not self.done():
286*cda5da8dSAndroid Build Coastguard Worker            self._asyncio_future_blocking = True
287*cda5da8dSAndroid Build Coastguard Worker            yield self  # This tells Task to wait for completion.
288*cda5da8dSAndroid Build Coastguard Worker        if not self.done():
289*cda5da8dSAndroid Build Coastguard Worker            raise RuntimeError("await wasn't used with future")
290*cda5da8dSAndroid Build Coastguard Worker        return self.result()  # May raise too.
291*cda5da8dSAndroid Build Coastguard Worker
292*cda5da8dSAndroid Build Coastguard Worker    __iter__ = __await__  # make compatible with 'yield from'.
293*cda5da8dSAndroid Build Coastguard Worker
294*cda5da8dSAndroid Build Coastguard Worker
295*cda5da8dSAndroid Build Coastguard Worker# Needed for testing purposes.
296*cda5da8dSAndroid Build Coastguard Worker_PyFuture = Future
297*cda5da8dSAndroid Build Coastguard Worker
298*cda5da8dSAndroid Build Coastguard Worker
299*cda5da8dSAndroid Build Coastguard Workerdef _get_loop(fut):
300*cda5da8dSAndroid Build Coastguard Worker    # Tries to call Future.get_loop() if it's available.
301*cda5da8dSAndroid Build Coastguard Worker    # Otherwise fallbacks to using the old '_loop' property.
302*cda5da8dSAndroid Build Coastguard Worker    try:
303*cda5da8dSAndroid Build Coastguard Worker        get_loop = fut.get_loop
304*cda5da8dSAndroid Build Coastguard Worker    except AttributeError:
305*cda5da8dSAndroid Build Coastguard Worker        pass
306*cda5da8dSAndroid Build Coastguard Worker    else:
307*cda5da8dSAndroid Build Coastguard Worker        return get_loop()
308*cda5da8dSAndroid Build Coastguard Worker    return fut._loop
309*cda5da8dSAndroid Build Coastguard Worker
310*cda5da8dSAndroid Build Coastguard Worker
311*cda5da8dSAndroid Build Coastguard Workerdef _set_result_unless_cancelled(fut, result):
312*cda5da8dSAndroid Build Coastguard Worker    """Helper setting the result only if the future was not cancelled."""
313*cda5da8dSAndroid Build Coastguard Worker    if fut.cancelled():
314*cda5da8dSAndroid Build Coastguard Worker        return
315*cda5da8dSAndroid Build Coastguard Worker    fut.set_result(result)
316*cda5da8dSAndroid Build Coastguard Worker
317*cda5da8dSAndroid Build Coastguard Worker
318*cda5da8dSAndroid Build Coastguard Workerdef _convert_future_exc(exc):
319*cda5da8dSAndroid Build Coastguard Worker    exc_class = type(exc)
320*cda5da8dSAndroid Build Coastguard Worker    if exc_class is concurrent.futures.CancelledError:
321*cda5da8dSAndroid Build Coastguard Worker        return exceptions.CancelledError(*exc.args)
322*cda5da8dSAndroid Build Coastguard Worker    elif exc_class is concurrent.futures.TimeoutError:
323*cda5da8dSAndroid Build Coastguard Worker        return exceptions.TimeoutError(*exc.args)
324*cda5da8dSAndroid Build Coastguard Worker    elif exc_class is concurrent.futures.InvalidStateError:
325*cda5da8dSAndroid Build Coastguard Worker        return exceptions.InvalidStateError(*exc.args)
326*cda5da8dSAndroid Build Coastguard Worker    else:
327*cda5da8dSAndroid Build Coastguard Worker        return exc
328*cda5da8dSAndroid Build Coastguard Worker
329*cda5da8dSAndroid Build Coastguard Worker
330*cda5da8dSAndroid Build Coastguard Workerdef _set_concurrent_future_state(concurrent, source):
331*cda5da8dSAndroid Build Coastguard Worker    """Copy state from a future to a concurrent.futures.Future."""
332*cda5da8dSAndroid Build Coastguard Worker    assert source.done()
333*cda5da8dSAndroid Build Coastguard Worker    if source.cancelled():
334*cda5da8dSAndroid Build Coastguard Worker        concurrent.cancel()
335*cda5da8dSAndroid Build Coastguard Worker    if not concurrent.set_running_or_notify_cancel():
336*cda5da8dSAndroid Build Coastguard Worker        return
337*cda5da8dSAndroid Build Coastguard Worker    exception = source.exception()
338*cda5da8dSAndroid Build Coastguard Worker    if exception is not None:
339*cda5da8dSAndroid Build Coastguard Worker        concurrent.set_exception(_convert_future_exc(exception))
340*cda5da8dSAndroid Build Coastguard Worker    else:
341*cda5da8dSAndroid Build Coastguard Worker        result = source.result()
342*cda5da8dSAndroid Build Coastguard Worker        concurrent.set_result(result)
343*cda5da8dSAndroid Build Coastguard Worker
344*cda5da8dSAndroid Build Coastguard Worker
345*cda5da8dSAndroid Build Coastguard Workerdef _copy_future_state(source, dest):
346*cda5da8dSAndroid Build Coastguard Worker    """Internal helper to copy state from another Future.
347*cda5da8dSAndroid Build Coastguard Worker
348*cda5da8dSAndroid Build Coastguard Worker    The other Future may be a concurrent.futures.Future.
349*cda5da8dSAndroid Build Coastguard Worker    """
350*cda5da8dSAndroid Build Coastguard Worker    assert source.done()
351*cda5da8dSAndroid Build Coastguard Worker    if dest.cancelled():
352*cda5da8dSAndroid Build Coastguard Worker        return
353*cda5da8dSAndroid Build Coastguard Worker    assert not dest.done()
354*cda5da8dSAndroid Build Coastguard Worker    if source.cancelled():
355*cda5da8dSAndroid Build Coastguard Worker        dest.cancel()
356*cda5da8dSAndroid Build Coastguard Worker    else:
357*cda5da8dSAndroid Build Coastguard Worker        exception = source.exception()
358*cda5da8dSAndroid Build Coastguard Worker        if exception is not None:
359*cda5da8dSAndroid Build Coastguard Worker            dest.set_exception(_convert_future_exc(exception))
360*cda5da8dSAndroid Build Coastguard Worker        else:
361*cda5da8dSAndroid Build Coastguard Worker            result = source.result()
362*cda5da8dSAndroid Build Coastguard Worker            dest.set_result(result)
363*cda5da8dSAndroid Build Coastguard Worker
364*cda5da8dSAndroid Build Coastguard Worker
365*cda5da8dSAndroid Build Coastguard Workerdef _chain_future(source, destination):
366*cda5da8dSAndroid Build Coastguard Worker    """Chain two futures so that when one completes, so does the other.
367*cda5da8dSAndroid Build Coastguard Worker
368*cda5da8dSAndroid Build Coastguard Worker    The result (or exception) of source will be copied to destination.
369*cda5da8dSAndroid Build Coastguard Worker    If destination is cancelled, source gets cancelled too.
370*cda5da8dSAndroid Build Coastguard Worker    Compatible with both asyncio.Future and concurrent.futures.Future.
371*cda5da8dSAndroid Build Coastguard Worker    """
372*cda5da8dSAndroid Build Coastguard Worker    if not isfuture(source) and not isinstance(source,
373*cda5da8dSAndroid Build Coastguard Worker                                               concurrent.futures.Future):
374*cda5da8dSAndroid Build Coastguard Worker        raise TypeError('A future is required for source argument')
375*cda5da8dSAndroid Build Coastguard Worker    if not isfuture(destination) and not isinstance(destination,
376*cda5da8dSAndroid Build Coastguard Worker                                                    concurrent.futures.Future):
377*cda5da8dSAndroid Build Coastguard Worker        raise TypeError('A future is required for destination argument')
378*cda5da8dSAndroid Build Coastguard Worker    source_loop = _get_loop(source) if isfuture(source) else None
379*cda5da8dSAndroid Build Coastguard Worker    dest_loop = _get_loop(destination) if isfuture(destination) else None
380*cda5da8dSAndroid Build Coastguard Worker
381*cda5da8dSAndroid Build Coastguard Worker    def _set_state(future, other):
382*cda5da8dSAndroid Build Coastguard Worker        if isfuture(future):
383*cda5da8dSAndroid Build Coastguard Worker            _copy_future_state(other, future)
384*cda5da8dSAndroid Build Coastguard Worker        else:
385*cda5da8dSAndroid Build Coastguard Worker            _set_concurrent_future_state(future, other)
386*cda5da8dSAndroid Build Coastguard Worker
387*cda5da8dSAndroid Build Coastguard Worker    def _call_check_cancel(destination):
388*cda5da8dSAndroid Build Coastguard Worker        if destination.cancelled():
389*cda5da8dSAndroid Build Coastguard Worker            if source_loop is None or source_loop is dest_loop:
390*cda5da8dSAndroid Build Coastguard Worker                source.cancel()
391*cda5da8dSAndroid Build Coastguard Worker            else:
392*cda5da8dSAndroid Build Coastguard Worker                source_loop.call_soon_threadsafe(source.cancel)
393*cda5da8dSAndroid Build Coastguard Worker
394*cda5da8dSAndroid Build Coastguard Worker    def _call_set_state(source):
395*cda5da8dSAndroid Build Coastguard Worker        if (destination.cancelled() and
396*cda5da8dSAndroid Build Coastguard Worker                dest_loop is not None and dest_loop.is_closed()):
397*cda5da8dSAndroid Build Coastguard Worker            return
398*cda5da8dSAndroid Build Coastguard Worker        if dest_loop is None or dest_loop is source_loop:
399*cda5da8dSAndroid Build Coastguard Worker            _set_state(destination, source)
400*cda5da8dSAndroid Build Coastguard Worker        else:
401*cda5da8dSAndroid Build Coastguard Worker            if dest_loop.is_closed():
402*cda5da8dSAndroid Build Coastguard Worker                return
403*cda5da8dSAndroid Build Coastguard Worker            dest_loop.call_soon_threadsafe(_set_state, destination, source)
404*cda5da8dSAndroid Build Coastguard Worker
405*cda5da8dSAndroid Build Coastguard Worker    destination.add_done_callback(_call_check_cancel)
406*cda5da8dSAndroid Build Coastguard Worker    source.add_done_callback(_call_set_state)
407*cda5da8dSAndroid Build Coastguard Worker
408*cda5da8dSAndroid Build Coastguard Worker
409*cda5da8dSAndroid Build Coastguard Workerdef wrap_future(future, *, loop=None):
410*cda5da8dSAndroid Build Coastguard Worker    """Wrap concurrent.futures.Future object."""
411*cda5da8dSAndroid Build Coastguard Worker    if isfuture(future):
412*cda5da8dSAndroid Build Coastguard Worker        return future
413*cda5da8dSAndroid Build Coastguard Worker    assert isinstance(future, concurrent.futures.Future), \
414*cda5da8dSAndroid Build Coastguard Worker        f'concurrent.futures.Future is expected, got {future!r}'
415*cda5da8dSAndroid Build Coastguard Worker    if loop is None:
416*cda5da8dSAndroid Build Coastguard Worker        loop = events._get_event_loop()
417*cda5da8dSAndroid Build Coastguard Worker    new_future = loop.create_future()
418*cda5da8dSAndroid Build Coastguard Worker    _chain_future(future, new_future)
419*cda5da8dSAndroid Build Coastguard Worker    return new_future
420*cda5da8dSAndroid Build Coastguard Worker
421*cda5da8dSAndroid Build Coastguard Worker
422*cda5da8dSAndroid Build Coastguard Workertry:
423*cda5da8dSAndroid Build Coastguard Worker    import _asyncio
424*cda5da8dSAndroid Build Coastguard Workerexcept ImportError:
425*cda5da8dSAndroid Build Coastguard Worker    pass
426*cda5da8dSAndroid Build Coastguard Workerelse:
427*cda5da8dSAndroid Build Coastguard Worker    # _CFuture is needed for tests.
428*cda5da8dSAndroid Build Coastguard Worker    Future = _CFuture = _asyncio.Future
429