python runtime_error ai_generated true

RuntimeError: Event loop is closed pytest.PytestUnhandledThreadExceptionWarning: Exception in thread Thread-1

ID: python/pytest-asyncio-event-loop-closed

Also available as: JSON · Markdown · 中文
80%Fix Rate
85%Confidence
0Evidence
2024-07-08First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
0.23 active — — —

Root Cause

pytest-asyncio creates a new event loop per test by default, but aiohttp/httpx AsyncClient or background tasks hold references to the previous loop. When teardown closes the loop, pending callbacks fire against a closed loop.

generic

中文

pytest-asyncio 默认每个测试创建一个新的事件循环,但 aiohttp/httpx AsyncClient 或后台任务保留了对先前循环的引用。当 teardown 关闭该循环时,待处理的回调会在已关闭的循环上触发。

Workarounds

  1. 90% success
    # conftest.py
    import pytest
    import asyncio
    
    @pytest.fixture(scope='session')
    def event_loop():
        loop = asyncio.new_event_loop()
        yield loop
        loop.close()
  2. 92% success
    @pytest.fixture
    async def client():
        async with httpx.AsyncClient() as c:
            yield c
        await c.aclose()
  3. 88% success
    # pyproject.toml
    [tool.pytest.ini_options]
    asyncio_mode = "auto"
    asyncio_default_fixture_loop_scope = "session"

Dead Ends

Common approaches that don't work:

  1. 90% fail

    Nested event loops raise RuntimeError: asyncio.run() cannot be called from a running event loop when pytest-asyncio already created one.

  2. 75% fail

    Mode changes fixture discovery, not loop lifecycle; the underlying resource leak still closes loops mid-flight.