Exemplo n.º 1
0
 def wrapper(*args, **kwargs):
     # type: (*Any, **Any) -> Future[_T]
     # This function is type-annotated with a comment to work around
     # https://bitbucket.org/pypy/pypy/issues/2868/segfault-with-args-type-annotation-in
     future = _create_future()
     if contextvars is not None:
         ctx_run = contextvars.copy_context().run  # type: Callable
     else:
         ctx_run = _fake_ctx_run
     try:
         result = ctx_run(func, *args, **kwargs)
     except (Return, StopIteration) as e:
         result = _value_from_stopiteration(e)
     except Exception:
         future_set_exc_info(future, sys.exc_info())
         try:
             return future
         finally:
             # Avoid circular references
             future = None  # type: ignore
     else:
         if isinstance(result, Generator):
             # Inline the first iteration of Runner.run.  This lets us
             # avoid the cost of creating a Runner when the coroutine
             # never actually yields, which in turn allows us to
             # use "optional" coroutines in critical path code without
             # performance penalty for the synchronous case.
             try:
                 yielded = ctx_run(next, result)
             except (StopIteration, Return) as e:
                 future_set_result_unless_cancelled(
                     future, _value_from_stopiteration(e))
             except Exception:
                 future_set_exc_info(future, sys.exc_info())
             else:
                 # Provide strong references to Runner objects as long
                 # as their result future objects also have strong
                 # references (typically from the parent coroutine's
                 # Runner). This keeps the coroutine's Runner alive.
                 # We do this by exploiting the public API
                 # add_done_callback() instead of putting a private
                 # attribute on the Future.
                 # (GitHub issues #1769, #2229).
                 runner = Runner(ctx_run, result, future, yielded)
                 future.add_done_callback(lambda _: runner)
             yielded = None
             try:
                 return future
             finally:
                 # Subtle memory optimization: if next() raised an exception,
                 # the future's exc_info contains a traceback which
                 # includes this stack frame.  This creates a cycle,
                 # which will be collected at the next full GC but has
                 # been shown to greatly increase memory usage of
                 # benchmarks (relative to the refcount-based scheme
                 # used in the absence of cycles).  We can avoid the
                 # cycle by clearing the local variable after we return it.
                 future = None  # type: ignore
     future_set_result_unless_cancelled(future, result)
     return future
Exemplo n.º 2
0
 def errback(failure: failure.Failure) -> None:
     try:
         failure.raiseException()
         # Should never happen, but just in case
         raise Exception("errback called without error")
     except:
         future_set_exc_info(f, sys.exc_info())
Exemplo n.º 3
0
 def handle_exception(self, typ: Type[Exception], value: Exception,
                      tb: types.TracebackType) -> bool:
     if not self.running and not self.finished:
         self.future = Future()
         future_set_exc_info(self.future, (typ, value, tb))
         self.ctx_run(self.run)
         return True
     else:
         return False
Exemplo n.º 4
0
    def run(self) -> None:
        """Starts or resumes the generator, running until it reaches a
        yield point that is not ready.
        """
        if self.running or self.finished:
            return
        try:
            self.running = True
            while True:
                future = self.future
                if future is None:
                    raise Exception("No pending future")
                if not future.done():
                    return
                self.future = None
                try:
                    exc_info = None

                    try:
                        value = future.result()
                    except Exception:
                        exc_info = sys.exc_info()
                    future = None

                    if exc_info is not None:
                        try:
                            yielded = self.gen.throw(*exc_info)  # type: ignore
                        finally:
                            # Break up a reference to itself
                            # for faster GC on CPython.
                            exc_info = None
                    else:
                        yielded = self.gen.send(value)

                except (StopIteration, Return) as e:
                    self.finished = True
                    self.future = _null_future
                    future_set_result_unless_cancelled(
                        self.result_future, _value_from_stopiteration(e)
                    )
                    self.result_future = None  # type: ignore
                    return
                except Exception:
                    self.finished = True
                    self.future = _null_future
                    future_set_exc_info(self.result_future, sys.exc_info())
                    self.result_future = None  # type: ignore
                    return
                if not self.handle_yield(yielded):
                    return
                yielded = None
        finally:
            self.running = False
Exemplo n.º 5
0
 def callback(fut: Future) -> None:
     unfinished_children.remove(fut)
     if not unfinished_children:
         result_list = []
         for f in children_futs:
             try:
                 result_list.append(f.result())
             except Exception as e:
                 if future.done():
                     if not isinstance(e, quiet_exceptions):
                         app_log.error("Multiple exceptions in yield list",
                                       exc_info=True)
                 else:
                     future_set_exc_info(future, sys.exc_info())
         if not future.done():
             if keys is not None:
                 future_set_result_unless_cancelled(
                     future, dict(zip(keys, result_list)))
             else:
                 future_set_result_unless_cancelled(future, result_list)
Exemplo n.º 6
0
        def run() -> None:
            try:
                result = func()
                if result is not None:
                    from tornado_py3.gen import convert_yielded

                    result = convert_yielded(result)
            except Exception:
                fut = Future()  # type: Future[Any]
                future_cell[0] = fut
                future_set_exc_info(fut, sys.exc_info())
            else:
                if is_future(result):
                    future_cell[0] = result
                else:
                    fut = Future()
                    future_cell[0] = fut
                    fut.set_result(result)
            assert future_cell[0] is not None
            self.add_future(future_cell[0], lambda future: self.stop())
Exemplo n.º 7
0
    def handle_yield(self, yielded: _Yieldable) -> bool:
        try:
            self.future = convert_yielded(yielded)
        except BadYieldError:
            self.future = Future()
            future_set_exc_info(self.future, sys.exc_info())

        if self.future is moment:
            self.io_loop.add_callback(self.run)
            return False
        elif self.future is None:
            raise Exception("no pending future")
        elif not self.future.done():

            def inner(f: Any) -> None:
                # Break a reference cycle to speed GC.
                f = None  # noqa: F841
                self.run()

            self.io_loop.add_future(self.future, inner)
            return False
        return True