python-trio / trio-asyncio

a re-implementation of the asyncio mainloop on top of Trio
Other
189 stars 38 forks source link

aio_as_trio does not work on generator functions and context factory functions #45

Open SillyFreak opened 5 years ago

SillyFreak commented 5 years ago

I was a little surprised that, when using aio_as_trio as a decorator, it only works on regular coroutine functions. For the followig test, only the non-commented parts work:

async with trio_asyncio.open_loop():
    @trio_asyncio.aio_as_trio
    async def func():
        await asyncio.sleep(0.1)
        return 1

    # @trio_asyncio.aio_as_trio
    # async def gen():
    #     yield 1
    #     await asyncio.sleep(0.1)
    #     yield 2

    # @trio_asyncio.aio_as_trio
    # @asynccontextmanager
    # async def ctx():
    #     await asyncio.sleep(0.1)
    #     yield 1

    assert await func() == 1

    # assert [item async for item in gen()] == [1, 2]

    # async with ctx() as value:
    #     assert value == 1

I found that the (maybe naive?) fix was not too hard; the following works as a replacement and makes the test above work:

def aio_as_trio(proc, *, loop=None):
    @functools.wraps(proc)
    def wrapper(*args, **kwargs):
        return Asyncio_Trio_Wrapper(proc(*args, **kwargs), loop=loop)

    return wrapper

If there is nothing I'm missing in this adaptation, I think this would make cross calling a lot cleaner.

ledmonster commented 5 years ago

Nest function call by trio_asyncio.aio_as_trio, instead of using decorator, and it worked.

async def test():
    async with trio_asyncio.open_loop():
        async def func():
            await asyncio.sleep(0.1)
            return 1

        assert await trio_asyncio.aio_as_trio(func()) == 1

        async def gen():
            yield 1
            await asyncio.sleep(0.1)
            yield 2

        assert [item async for item in trio_asyncio.aio_as_trio(gen())] == [1, 2]

        @asynccontextmanager
        async def ctx():
            await asyncio.sleep(0.1)
            yield 1

        async with trio_asyncio.aio_as_trio(ctx()) as value:
            assert value == 1

This behavior is described here:

SillyFreak commented 5 years ago

Yes, but decorator would be nicer to write, because it's at the declaration site instead of at every call site. At least having the option would be good.