Mixinig async-context manager and directly in asyncio

How to mix

async with api.open() as o: ... 

and

 o = await api.open() 

in one function?

Since first you need an object with __aenter__ and __aexit__ , but the second requires __await__ , which should be a generator without await .

My attempt:

 def AsyncContext(aenter, aexit): class AsyncContextClass: async def __aenter__(self): return await aenter() async def __aexit__(self, *args): return await aexit(*args) def __await__(self): return (yield from aenter()) return AsyncContextClass() 

But it fails with __await__ if aenter is defined using async def ( TypeError: cannot 'yield from' a coroutine object in a non-coroutine generator ).

It works great with @asyncio.coroutine decorator for aenter , but it's dirty.

+5
source share
1 answer

You can return __aenter__ __await__ from your __await__ class:

 # vim: tabstop=4 expandtab import asyncio class Test(object): async def __aenter__(self): print("enter") async def __aexit__(self, *args): print("exit") def __await__(self): return self.__aenter__().__await__() async def run(): async with Test(): print("hello") await Test() loop = asyncio.get_event_loop() loop.run_until_complete(run()) loop.close() 

Output:

 enter hello exit enter 
+10
source

Source: https://habr.com/ru/post/1237281/


All Articles