def coroutine(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return_future = Future()

        def handle_future(future):
            # Chained futures!
            try:
                if future.exception() is not None:
                    result = gen.throw(future.exception())
                else:
                    result = gen.send(future.result())
                if isinstance(result, tuple):
                    result = parallel(*result)
                result.add_done_callback(handle_future)
            except StopIteration as e:
                return_future.set_result(getattr(e, 'value', None))
            except Exception as e:
                return_future.set_exception(e)

        try:
            # Handle initial value.
            gen = func(*args, **kwargs)
        except Exception as e:
            return_future.set_exception(e)
            return return_future
        else:
            # If this isn't a generator, then wrap the result with a future.
            if not isinstance(gen, types.GeneratorType):
                return_future.set_result(gen)
                return return_future

        try:
            result = next(gen)
            if isinstance(result, tuple):
                result = parallel(*result)
            result.add_done_callback(handle_future)
        except StopIteration as e:
            return_future.set_result(getattr(e, 'value', None))
        except Exception as e:
            return_future.set_exception(e)

        return return_future
    return wrapper
Decorator for coroutine functions that need to block for asynchronous operations.
dataset/ETHPy150Open Shizmob/pydle/pydle/async.py/coroutine