def _make_coroutine_wrapper(func, replace_callback):
    """The inner workings of ``@gen.coroutine`` and ``@gen.engine``.

    The two decorators differ in their treatment of the ``callback``
    argument, so we cannot simply implement ``@engine`` in terms of
    ``@coroutine``.
    """
    # On Python 3.5, set the coroutine flag on our generator, to allow it
    # to be used with 'await'.
    wrapped = func
    if hasattr(types, 'coroutine'):
        func = types.coroutine(func)

    @functools.wraps(wrapped)
    def wrapper(*args, **kwargs):
        future = TracebackFuture()

        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = _value_from_stopiteration(e)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, GeneratorType):
                # 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:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)'))
                except (StopIteration, Return) as e:
                    future.set_result(_value_from_stopiteration(e))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    _futures_to_runners[future] = Runner(result, future, yielded)
                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
        future.set_result(result)
        return future

    wrapper.__wrapped__ = wrapped
    wrapper.__tornado_coroutine__ = True
    return wrapper
def _make_coroutine_wrapper ( func , replace_callback ) : wrapped = func if hasattr ( types , 'coroutine' ) : func = types . coroutine ( func ) @ functools . wraps ( wrapped ) def wrapper ( * args , ** kwargs ) : future = TracebackFuture ( ) if replace_callback and 'callback' in kwargs : callback = kwargs . pop ( 'callback' ) IOLoop . current ( ) . add_future ( future , lambda future : callback ( future . result ( ) ) ) try : result = func ( * args , ** kwargs ) except ( Return , StopIteration ) as e : result = _value_from_stopiteration ( e ) except Exception : future . set_exc_info ( sys . exc_info ( ) ) return future else : if isinstance ( result , GeneratorType ) : try : orig_stack_contexts = stack_context . _state . contexts yielded = next ( result ) if stack_context . _state . contexts is not orig_stack_contexts : yielded = TracebackFuture ( ) yielded . set_exception ( stack_context . StackContextInconsistentError ( 'stack_context inconsistency (probably caused ' 'by yield within a "with StackContext" block)' ) ) except ( StopIteration , Return ) as e : future . set_result ( _value_from_stopiteration ( e ) ) except Exception : future . set_exc_info ( sys . exc_info ( ) ) else : _futures_to_runners [ future ] = Runner ( result , future , yielded ) yielded = None try : return future finally : future = None future . set_result ( result ) return future wrapper . __wrapped__ = wrapped wrapper . __tornado_coroutine__ = True return wrapper
The inner workings of ``@gen.coroutine`` and ``@gen.engine``.

    The two decorators differ in their treatment of the ``callback``
    argument, so we cannot simply implement ``@engine`` in terms of
    ``@coroutine``.