def coroutine(func):

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            ctx = args[0].blueox_ctx
        except (AttributeError, IndexError):
            ctx = None

        # Remember, not every coroutine wrapped method will return a generator,
        # so we have to manage context switching in multiple places.
        if ctx is not None:
            ctx.start()

        result = func(*args, **kwargs)

        if ctx is not None:
            ctx.stop()

        if isinstance(result, types.GeneratorType):
            return _gen_wrapper(ctx, result)

        return result

    real_coroutine = tornado.gen.coroutine
    return real_coroutine(wrapper)
Replacement for tornado.gen.coroutine that manages a blueox context
dataset/ETHPy150Open rhettg/BlueOx/blueox/tornado_utils.py/coroutine