def _accept_error(self, error): if self._value is not _futures_none: # is_computed(), but faster # We can't change the value in this case, so we can just return here. pass else: # when there is no _task it means that this is the bottommost level of the async # task. We must attach the traceback as soon as possible if not hasattr(error, '_task'): error._task = self core_errors.prepare_for_reraise(error) else: # when we already have the _task on the error, it means that # some child generator of ours had an error. # now, we are storing the _traceback on the error. we use this so we can # raise it with that exact traceback later. # now, we when do raise it, the upper level gets a new traceback # with the curent level's traceback connected via a linked list pointer. # known as tb_next in traceback object. # this is really important. if we keep updating this traceback, # we can glue all the different tasks' tracebacks and make it look like # the error came from there. error._traceback = sys.exc_info()[2] if _debug_options.DUMP_EXCEPTIONS: debug.dump_error(error) # Must queue, since there can be captured dependencies to resolve self._queue_throw_error(error)
def wrapped(*args): error = None try: yield async_call.asynq(handler, *args) except BaseException as e: prepare_for_reraise(e) error = e result(error) return
def _resume_contexts(self): if self._contexts_active: return self._contexts_active = True # same try/except deal as with _pause_contexts, but in this case # we re-raise the first exception raised. error = None for ctx in self._contexts.values(): try: ctx.resume() except BaseException as e: if error is None: error = e core_errors.prepare_for_reraise(error) if error is not None: self._accept_error(error)
def f2(): try: f1() except AssertionError as e: prepared_e = errors.prepare_for_reraise(e) else: assert False, 'f1 should have raised AssertionError' raise_later(prepared_e)
def _pause_contexts(self): if not self._contexts_active: return self._contexts_active = False # execute each pause() in a try/except and if 1 or more of them # raise an exception, then save the last exception raised so that it # can be re-raised later. We re-raise the last exception to make the # behavior consistent with __exit__. error = None for ctx in reversed(list(self._contexts.values())): try: ctx.pause() except BaseException as e: error = e core_errors.prepare_for_reraise(error) if error is not None: self._accept_error(error)
def _resume_contexts(self): i = 0 contexts = self._contexts l = len(contexts) # same try/except deal as with _pause_contexts, but in this case # we re-raise the first exception raised. error = None while i < l: try: contexts[i].__resume__() except BaseException as e: if error is None: error = e core_errors.prepare_for_reraise(error) i += 1 if error is not None: self._accept_error(error)
def _pause_contexts(self): contexts = self._contexts i = len(contexts) - 1 # execute each __pause__() in a try/except and if 1 or more of them # raise an exception, then save the last exception raised so that it # can be re-raised later. We re-raise the last exception to make the # behavior consistent with __exit__. error = None while i >= 0: try: contexts[i].__pause__() except BaseException as e: error = e core_errors.prepare_for_reraise(error) i -= 1 if error is not None: self._accept_error(error)