Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

close() hangs infinitely in nested async context manager #306

Open
peku33 opened this issue Sep 19, 2024 · 0 comments
Open

close() hangs infinitely in nested async context manager #306

peku33 opened this issue Sep 19, 2024 · 0 comments

Comments

@peku33
Copy link

peku33 commented Sep 19, 2024

Description

This relatively simple scenario causes the program to lock up in some weird state:

import asyncio
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

import aiosqlite


@asynccontextmanager
async def acmgr_other() -> AsyncIterator[None]:
    async with asyncio.Lock(): # not actually needed, just to demonstrate any other context manager works
        yield


@asynccontextmanager
async def acmgr_aiosqlite() -> AsyncIterator[None]:
    async with aiosqlite.connect("test.sqlite"):
        yield


@asynccontextmanager
async def acmgr2() -> AsyncIterator[None]:
    async with acmgr_aiosqlite():  # hangs on acmgr_aiosqlite, passes on acmgr_other
        yield


async def gen() -> AsyncIterator[None]:
    async with acmgr2():
        yield None


async def _amain() -> None:
    async for _ in gen():
        raise ValueError()


asyncio.run(_amain())

process never ends.

After some experimenting around with acmgr_aiosqlite it seems like close() causes some weird behaviour around event loop:

@asynccontextmanager
async def acmgr_aiosqlite() -> AsyncIterator[None]:
    connection = await aiosqlite.connect("test.sqlite")

    exc = None
    try:
        yield
    except BaseException as exc2:
        exc = exc2
    finally:
        try:
            print("close() begin")
            await connection.close()
            print("close() end")
        except BaseException as exc2:
            print("exception begin")
            print(exc2, type(exc2))
            print("exception end")
        finally:
            print("finally")

    if exc is not None:
        raise exc

produces

PS path> python .\test4.py
close() begin
Task exception was never retrieved
future: <Task finished name='Task-3' coro=<<async_generator_athrow without __name__>()> exception=RuntimeError('aclose(): asynchronous generator is already running')>
Traceback (most recent call last):
(...)

Details

  • OS: win11
  • Python version: 3.11.9
  • aiosqlite version: 0.20.0
  • Can you repro on 'main' branch? probably yes
  • Can you repro in a clean virtualenv? yes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant