Issue
I have a situation where I want to break from an async for loop. I managed to reduce the issue to the application below. I expect to enter the 'finally' section of the context manager when breaking from the loop in main. In other words, the expected result is
try
456
finally
done
but what I get is
try
456
done
finally
and then an exception when the application closes.
Here is the code
import asyncio
from contextlib import asynccontextmanager
@asynccontextmanager
async def receiving():
try:
print('try')
yield 123
finally:
print('finally')
async def request_all():
async with receiving():
yield 456
async def main():
async for r in request_all():
print(r)
break
print('done')
asyncio.run(main())
I found this bug report that seems similar, but as far as I can tell it has been resolved before 3.8. I tested my issue on 3.8.2 and 3.9.6
Solution
I can see how this behaviour is confusing, but I don't think it's a bug. If you bypass the exhaustion of the async Iterator with break
, you never leave the async with
in request_all
, so the finally
-block will not get executed until the event loop finishes. This has the advantage that you could exhaust the generator at a later point.
If you are sure, you don't need your generator anymore, you could close the async_generator instead of break
ing to get your expected behaviour:
import asyncio
from contextlib import asynccontextmanager
@asynccontextmanager
async def receiving():
try:
print('try')
yield 123
finally:
print('finally')
async def request_all():
async with receiving():
yield 456
async def main():
gen = request_all()
async for r in gen:
print(r)
await gen.aclose() #instead of break
print('done')
asyncio.run(main())
Answered By - thisisalsomypassword
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.