def coroutine(func):
    """Replacement for tornado.gen.coroutine that manages a blueox context

    The difficulty with managing global blueox contexts in an async environment
    is contexts will need to start and stop depending on what steps of a
    coroutine are running. This decorator wraps the default coroutine decorator
    allowing us to stop and restore the context whenever this coroutine runs.

    If you don't use this wrapper, unrelated contexts may be grouped together!
    """

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            ctx = args[0].blueox_ctx
        except (AttributeError, __HOLE__):
            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)
dataset/ETHPy150Open rhettg/BlueOx/blueox/tornado_utils.py/coroutine