def _done_callback(i, fut): nonlocal nfinished if outer.done(): if not fut.cancelled(): # Mark exception retrieved. fut.exception() return if fut.cancelled(): res = futures.CancelledError() if not return_exceptions: outer.set_exception(res) return elif fut._exception is not None: res = fut.exception() # Mark exception retrieved. if not return_exceptions: outer.set_exception(res) return else: res = fut._result results[i] = res nfinished += 1 if nfinished == nchildren: if outer._cancel_requested: outer.set_exception(futures.CancelledError()) else: outer.set_result(results)
def result(self, timeout=None): with self._condition: if self._state == CANCELLED: raise futures.CancelledError() elif self._state == FINISHED: return None self._condition.wait(timeout) if self._state == CANCELLED: raise futures.CancelledError() elif self._state == FINISHED: return None else: raise futures.TimeoutError()
def exception(self, timeout=None): with self._condition: if self._state == CANCELLED: raise cfutures.CancelledError() elif self._state == FINISHED: return self._exception self._condition.wait(timeout) if self._state == CANCELLED: raise cfutures.CancelledError() elif self._state == FINISHED: return self._exception else: raise cfutures.TimeoutError()
def _done_callback(fut): nonlocal nfinished nfinished += 1 if outer.done(): if not fut.cancelled(): # Mark exception retrieved. fut.exception() return if not return_exceptions: if fut.cancelled(): # Check if 'fut' is cancelled first, as # 'fut.exception()' will *raise* a CancelledError # instead of returning it. exc = futures.CancelledError() outer.set_exception(exc) return else: exc = fut.exception() if exc is not None: outer.set_exception(exc) return if nfinished == nfuts: # All futures are done; create a list of results # and set it to the 'outer' future. results = [] for fut in children: if fut.cancelled(): # Check if 'fut' is cancelled first, as # 'fut.exception()' will *raise* a CancelledError # instead of returning it. res = futures.CancelledError() else: res = fut.exception() if res is None: res = fut.result() results.append(res) if outer._cancel_requested: # If gather is being cancelled we must propagate the # cancellation regardless of *return_exceptions* argument. # See issue 32684. outer.set_exception(futures.CancelledError()) else: outer.set_result(results)
def _step(self, value=None, exc=None): assert not self.done(), \ '_step(): already done: {!r}, {!r}, {!r}'.format(self, value, exc) if self._must_cancel: if not isinstance(exc, futures.CancelledError): exc = futures.CancelledError() self._must_cancel = False coro = self._coro self._fut_waiter = None # Call either coro.throw(exc) or coro.send(value). try: if exc is not None: result = coro.throw(exc) elif value is not None: result = coro.send(value) else: result = next(coro) except StopIteration as exc: self.set_result(exc.value) except futures.CancelledError as exc: super().cancel() # I.e., Future.cancel(self). except Exception as exc: self.set_exception(exc) except BaseException as exc: self.set_exception(exc) raise else: if isinstance(result, futures.Future): # Yielded Future must come from Future.__iter__(). if result._blocking: result._blocking = False result.add_done_callback(self._wakeup) self._fut_waiter = result if self._must_cancel: if self._fut_waiter.cancel(): self._must_cancel = False else: self._loop.call_soon( self._step, None, RuntimeError('yield was used instead of yield from ' 'in task {!r} with {!r}'.format( self, result))) elif result is None: # Bare yield relinquishes control for one event loop iteration. self._loop.call_soon(self._step) elif inspect.isgenerator(result): # Yielding a generator is just wrong. self._loop.call_soon( self._step, None, RuntimeError('yield was used instead of yield from for ' 'generator in task {!r} with {}'.format( self, result))) else: # Yielding something else is an error. self._loop.call_soon( self._step, None, RuntimeError('Task got bad yield: {!r}'.format(result))) self = None
def handle_result(future): if future.cancelled(): reactor.callFromThread(deferred.errback, futures.CancelledError()) return error = future.exception() if error is not None: reactor.callFromThread(deferred.errback, error) return result = future.result() reactor.callFromThread(deferred.callback, result)
def _done_callback(fut): nonlocal nfinished nfinished += 1 if outer.done(): if not fut.cancelled(): # Mark exception retrieved. fut.exception() return if not return_exceptions: if fut.cancelled(): # Check if 'fut' is cancelled first, as # 'fut.exception()' will *raise* a CancelledError # instead of returning it. exc = futures.CancelledError() outer.set_exception(exc) return else: exc = fut.exception() if exc is not None: outer.set_exception(exc) return if nfinished == nfuts: # All futures are done; create a list of results # and set it to the 'outer' future. results = [] for fut in children: if fut.cancelled(): # Check if 'fut' is cancelled first, as # 'fut.exception()' will *raise* a CancelledError # instead of returning it. res = futures.CancelledError() else: res = fut.exception() if res is None: res = fut.result() results.append(res) outer.set_result(results)
def handle_result(f): if not self.set_running_or_notify_cancel(): return if src.cancelled(): self.set_exception(futures.CancelledError()) return error = src.exception() if error is not None: self.set_exception(error) return try: result = src.result() if func is not None: result = func(result, *args, **kw) self.set_result(result) except Exception as e: self.set_exception(e)
def _start_action(self): """ Start the physical action, and immediately return. It also set the state to RUNNING. Note: to be called without the lock (._condition) acquired. """ with self._condition: if self._state == CANCELLED: raise futures.CancelledError() # Do the action if self._type == MOVE_REL: duration = self._moveRel(self._args) else: raise Exception("Unknown action %s" % self._type) self._state = RUNNING duration = min(duration, 60) # => wait maximum 2 min self._expected_end = time.time() + duration self._timeout = self._expected_end + duration + 1, # 2 *duration + 1s
def _done_callback(i, fut): nonlocal nfinished if outer._state != futures._PENDING: if fut._exception is not None: # Mark exception retrieved. fut.exception() return if fut._state == futures._CANCELLED: res = futures.CancelledError() if not return_exceptions: outer.set_exception(res) return elif fut._exception is not None: res = fut.exception() # Mark exception retrieved. if not return_exceptions: outer.set_exception(res) return else: res = fut._result results[i] = res nfinished += 1 if nfinished == nchildren: outer.set_result(results)
def _step(self, exc=None): assert not self.done(), \ '_step(): already done: {!r}, {!r}'.format(self, exc) if self._must_cancel: if not isinstance(exc, futures.CancelledError): exc = futures.CancelledError() self._must_cancel = False coro = self._coro self._fut_waiter = None self.__class__._current_tasks[self._loop] = self # Call either coro.throw(exc) or coro.send(None). try: if exc is None: # We use the `send` method directly, because coroutines # don't have `__iter__` and `__next__` methods. result = coro.send(None) else: result = coro.throw(exc) except StopIteration as exc: self.set_result(exc.value) except futures.CancelledError: super().cancel() # I.e., Future.cancel(self). except Exception as exc: self.set_exception(exc) except BaseException as exc: self.set_exception(exc) raise else: blocking = getattr(result, '_asyncio_future_blocking', None) if blocking is not None: # Yielded Future must come from Future.__iter__(). if result._loop is not self._loop: self._loop.call_soon( self._step, RuntimeError('Task {!r} got Future {!r} attached to a ' 'different loop'.format(self, result))) elif blocking: if result is self: self._loop.call_soon( self._step, RuntimeError( 'Task cannot await on itself: {!r}'.format( self))) else: result._asyncio_future_blocking = False result.add_done_callback(self._wakeup) self._fut_waiter = result if self._must_cancel: if self._fut_waiter.cancel(): self._must_cancel = False else: self._loop.call_soon( self._step, RuntimeError('yield was used instead of yield from ' 'in task {!r} with {!r}'.format( self, result))) elif result is None: # Bare yield relinquishes control for one event loop iteration. self._loop.call_soon(self._step) elif inspect.isgenerator(result): # Yielding a generator is just wrong. self._loop.call_soon( self._step, RuntimeError('yield was used instead of yield from for ' 'generator in task {!r} with {}'.format( self, result))) else: # Yielding something else is an error. self._loop.call_soon( self._step, RuntimeError('Task got bad yield: {!r}'.format(result))) finally: self.__class__._current_tasks.pop(self._loop) self = None # Needed to break cycles when an exception occurs.
def __step(self, exc=None): if self.done(): raise futures.InvalidStateError( f'_step(): already done: {self!r}, {exc!r}') if self._must_cancel: if not isinstance(exc, futures.CancelledError): exc = futures.CancelledError() self._must_cancel = False coro = self._coro self._fut_waiter = None _enter_task(self._loop, self) # Call either coro.throw(exc) or coro.send(None). try: if exc is None: # We use the `send` method directly, because coroutines # don't have `__iter__` and `__next__` methods. result = coro.send(None) else: result = coro.throw(exc) except StopIteration as exc: if self._must_cancel: # Task is cancelled right before coro stops. self._must_cancel = False super().set_exception(futures.CancelledError()) else: super().set_result(exc.value) except futures.CancelledError: super().cancel() # I.e., Future.cancel(self). except Exception as exc: super().set_exception(exc) except BaseException as exc: super().set_exception(exc) raise else: blocking = getattr(result, '_asyncio_future_blocking', None) if blocking is not None: # Yielded Future must come from Future.__iter__(). if futures._get_loop(result) is not self._loop: new_exc = RuntimeError( f'Task {self!r} got Future ' f'{result!r} attached to a different loop') self._loop.call_soon(self.__step, new_exc, context=self._context) elif blocking: if result is self: new_exc = RuntimeError( f'Task cannot await on itself: {self!r}') self._loop.call_soon(self.__step, new_exc, context=self._context) else: result._asyncio_future_blocking = False result.add_done_callback(self.__wakeup, context=self._context) self._fut_waiter = result if self._must_cancel: if self._fut_waiter.cancel(): self._must_cancel = False else: new_exc = RuntimeError( f'yield was used instead of yield from ' f'in task {self!r} with {result!r}') self._loop.call_soon(self.__step, new_exc, context=self._context) elif result is None: # Bare yield relinquishes control for one event loop iteration. self._loop.call_soon(self.__step, context=self._context) elif inspect.isgenerator(result): # Yielding a generator is just wrong. new_exc = RuntimeError( f'yield was used instead of yield from for ' f'generator in task {self!r} with {result!r}') self._loop.call_soon(self.__step, new_exc, context=self._context) else: # Yielding something else is an error. new_exc = RuntimeError(f'Task got bad yield: {result!r}') self._loop.call_soon(self.__step, new_exc, context=self._context) finally: _leave_task(self._loop, self) self = None # Needed to break cycles when an exception occurs.
def _step(self, value=None, exc=None): assert not self.done(), \ '_step(): already done: {!r}, {!r}, {!r}'.format(self, value, exc) if self._must_cancel: if not isinstance(exc, futures.CancelledError): exc = futures.CancelledError() self._must_cancel = False coro = self._coro self._fut_waiter = None self.__class__._current_tasks[self._loop] = self # Call either coro.throw(exc) or coro.send(value). # FIXME: Brython has a bug in try: else: finally: ordering # so the finally part: # # self.__class__._current_tasks.pop(self._loop) # self = None # Needed to break cycles when an exception occurs. # # is copied here to every exception. When the bug gets fixed # it can go back to the finally part try: if exc is not None: result = coro.throw(exc) elif value is not None: result = coro.send(value) else: result = next(coro) except StopIteration as exc: self.set_result(getattr(exc, 'value', None)) self.__class__._current_tasks.pop(self._loop) self = None # Needed to break cycles when an exception occurs. except futures.CancelledError as exc: super().cancel() # I.e., Future.cancel(self). self.__class__._current_tasks.pop(self._loop) self = None # Needed to break cycles when an exception occurs. except Exception as exc: self.set_exception(exc) self.__class__._current_tasks.pop(self._loop) self = None # Needed to break cycles when an exception occurs. except BaseException as exc: self.set_exception(exc) self.__class__._current_tasks.pop(self._loop) self = None # Needed to break cycles when an exception occurs. raise else: if isinstance(result, futures.Future): # Yielded Future must come from Future.__iter__(). # # FIXME: # In the original implementation the code checked for # result._blocking; if that was false, the following # code ran: # # self._loop.call_soon( # self._step, None, # RuntimeError('yield was used instead of yield from in task {!r} with {!r}'.format(self, result))) # # however, it is not clear, where the _blocking attribute # is supposed to be set. Either this is a bug in Brython's # implementation of yield from, or it is a bug in the original # code; either way, we have to workaround it here: # # original code: # # if result._blocking: # result._blocking = False # result.add_done_callback(self._wakeup) # self._fut_waiter = result # if self._must_cancel: # if self._fut_waiter.cancel(): # self._must_cancel = False # else: # self._loop.call_soon( # self._step, None, # RuntimeError('yield was used instead of yield from in task {!r} with {!r}'.format(self, result))) result._blocking = False result.add_done_callback(self._wakeup) self._fut_waiter = result if self._must_cancel: if self._fut_waiter.cancel(): self._must_cancel = False elif result is None: # Bare yield relinquishes control for one event loop iteration. self._loop.call_soon(self._step) elif inspect.isgenerator(result): # Yielding a generator is just wrong. self._loop.call_soon( self._step, None, RuntimeError('yield was used instead of yield from for ' 'generator in task {!r} with {}'.format( self, result))) else: # Yielding something else is an error. self._loop.call_soon( self._step, None, RuntimeError('Task got bad yield: {!r}'.format(result))) self.__class__._current_tasks.pop(self._loop) self = None # Needed to break cycles when an exception occurs. finally: pass
def _step(self, exc=None): assert not self.done(), '_step(): already done: {!r}, {!r}'.format(self , exc) if self._must_cancel: if not isinstance(exc, futures.CancelledError): exc = futures.CancelledError() self._must_cancel = False coro = self._coro self._fut_waiter = None self.__class__._current_tasks[self._loop] = self try: if exc is None: result = coro.send(None) else: result = coro.throw(exc) except StopIteration as exc: if self._must_cancel: self._must_cancel = False self.set_exception(futures.CancelledError()) else: self.set_result(exc.value) except futures.CancelledError: super().cancel() except Exception as exc: self.set_exception(exc) except BaseException as exc: self.set_exception(exc) raise else: blocking = getattr(result, '_asyncio_future_blocking', None) if blocking is not None: if result._loop is not self._loop: self._loop.call_soon(self._step, RuntimeError( 'Task {!r} got Future {!r} attached to a different loop' .format(self, result))) elif blocking: if result is self: self._loop.call_soon(self._step, RuntimeError( 'Task cannot await on itself: {!r}'.format(self))) else: result._asyncio_future_blocking = False result.add_done_callback(self._wakeup) self._fut_waiter = result if self._must_cancel: if self._fut_waiter.cancel(): self._must_cancel = False else: self._loop.call_soon(self._step, RuntimeError( 'yield was used instead of yield from in task {!r} with {!r}' .format(self, result))) elif result is None: self._loop.call_soon(self._step) elif inspect.isgenerator(result): self._loop.call_soon(self._step, RuntimeError( 'yield was used instead of yield from for generator in task {!r} with {}' .format(self, result))) else: self._loop.call_soon(self._step, RuntimeError( 'Task got bad yield: {!r}'.format(result))) finally: self.__class__._current_tasks.pop(self._loop) self = None