Skip to content

Loop factory parametrization tears down async fixtures used by sync tests #1501

Description

@tjkuson

I encountered an issue with defining pytest_asyncio_loop_factories in test suites where non-async tests use async fixtures in shared loop scopes.

To reproduce:

# conftest.py

import asyncio
from collections.abc import Mapping, Callable

import pytest


def pytest_asyncio_loop_factories(
    config: pytest.Config,
    item: pytest.Item,
) -> Mapping[str, Callable[[], asyncio.AbstractEventLoop]]:
    return {"default": asyncio.new_event_loop}
# test_mre.py

from collections.abc import AsyncGenerator

import pytest
import pytest_asyncio


@pytest_asyncio.fixture(scope="session")
async def parent() -> AsyncGenerator[str]:
    yield "parent"


@pytest_asyncio.fixture(scope="session")
async def child(parent: str) -> AsyncGenerator[str]:
    yield "child"


@pytest.mark.asyncio(loop_scope="session")
async def test_async(parent) -> None:
    assert parent == "parent"


def test_sync(child: str) -> None:
    assert child == "child"

Running test_mre.py on the above using pytest-asyncio 1.4.0 and pytest 9.1.1 shows one pass and one failure with the following errror:

AssertionError: The fixture value for "parent" is not available.  This can happen when the fixture has already been torn down.

If pytest_asyncio_loop_factories is not defined in the conftest file, both tests pass.

If test_async is after test_sync, both tests pass.

The expected behaviour is that both tests pass regardless of order and pytest_asyncio_loop_factories hook implementation.

I think the fix would involve handling the loop factory for any test item that uses a pytest-asyncio-managed async fixture, not just async tests themselves.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions