pytest-dev/pytest-asyncio

Type error: `Value of type variable "_R" of function cannot be "AsyncClient"`

Opened this issue · 4 comments

Upgrading to pytest-asyncio==0.26.0:

import pytest_asyncio
from httpx import AsyncClient


@pytest_asyncio.fixture(scope="function")
def server_async_client() -> AsyncClient: ...

I get this error from mypy:

a.py:5:2: error: Value of type variable "_R" of function cannot be "AsyncClient"  [type-var]
    @pytest_asyncio.fixture(scope="function")
     ^

This is with Python 3.12.7 and the following packages:

httpx                     0.27.2
mypy                      1.15.0
pytest                    8.3.5
pytest-asyncio            0.25.3

Thanks for reporting this! Could this be a regression of #1045?

Yeah correct, that PR binds the "return" TypeVar _R to be awaitable, assuming it's always wrapping an async function.

That assumption is incorrect because it's possible to wrap non-async functions with pytest_asyncio.fixture:

@pytest_asyncio.fixture
def some_int() -> int:
    return 5

An alternate design could be pytest_asyncio.fixture blowing up if not wrapping an async function, as otherwise one should just use a normal pytest.fixture:

@pytest.fixture
def some_int() -> int:
    return 5

In my opinion, pytest-asyncio should raise an error when the user tries to decorate synchronous tests with pytest_asyncio.fixture. There should only be one way to decorate those fixtures and pytest already provides it.

That said, we cannot simply error out in this case. We should first raise a DeprecationWarning to give users a chance to update their code. A later release can turn the warning into an error.

This is not limited to wrapping non-async functions. I'm also seeing this kind of error when wrapping an
async iterable as below.

import asyncio
from typing import AsyncIterable

import pytest_asyncio


@pytest_asyncio.fixture(scope="session")
async def dummy_fixture() -> AsyncIterable[str]:
    await asyncio.sleep(1)
    yield "dummy"

Running mypy on this code produces:

error: Value of type variable "_R" of function cannot be "AsyncIterable[str]"  [type-var]