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