python / python/mypy

stubgen generates stubs for `@asynccontextmanager` functions that mypy itself rejects

Abierto
#21,869 3 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

bug topic-stubgen
Lenguaje dominante
Python
Estrellas
20.6k
Forks
3.3k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Bug Report

stubgen copies @asynccontextmanager and the async def keyword verbatim into the generated .pyi. Because a stub body has no yield, mypy then classifies the stubbed function as a coroutine function returning AsyncIterator[T] rather than as an async generator function, and rejects the decorator application.

The result is that stubgen emits a stub which mypy — the same version, with default settings — reports an error on. Source that type-checks cleanly produces a stub that does not.

To Reproduce

# cm.py
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager


@asynccontextmanager
async def ctx() -> AsyncIterator[int]:
    yield 1
$ mypy cm.py
Success: no issues found in 1 source file

$ stubgen -o out cm.py
Processed 1 modules
Generated out/cm.pyi

$ cat out/cm.pyi
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

@asynccontextmanager
async def ctx() -> AsyncIterator[int]: ...

$ mypy out/cm.pyi
out/cm.pyi:4: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[], Coroutine[Any, Any, AsyncIterator[int]]]"; expected "Callable[[], AsyncIterator[Never]]"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

The same happens for methods, and with AsyncGenerator[T, None] in place of AsyncIterator[T].

Expected Behavior

stubgen output should type-check under the mypy version that produced it. For an @asynccontextmanager-decorated async generator, that means emitting one of the two spellings the typing docs sanction for stubs — either dropping async:

@asynccontextmanager
def ctx() -> AsyncIterator[int]: ...

or dropping the decorator and declaring the decorated result, as typeshed does:

from contextlib import AbstractAsyncContextManager

def ctx() -> AbstractAsyncContextManager[int]: ...

Both of these are accepted by mypy 2.3.0.

Actual Behavior

out/cm.pyi:4: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[], Coroutine[Any, Any, AsyncIterator[int]]]"; expected "Callable[[], AsyncIterator[Never]]"  [arg-type]

Your Environment

  • Mypy version used: 2.3.0 (compiled: yes)
  • Mypy command-line flags: none (mypy out/cm.pyi); stub produced with stubgen -o out cm.py
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.11.15

Additional notes

This is a change in behaviour from 1.15.0. That version's stubgen omitted the decorator entirely:

# stubgen 1.15.0
async def ctx() -> AsyncIterator[int]: ...

which is also lossy, but happens to type-check, so the problem only becomes visible on 2.3.0 once the decorator is preserved.

The synchronous case is unaffected — @contextmanager over def f() -> Iterator[T] round-trips through stubgen and type-checks on 2.3.0, because there is no async keyword to change how the return type is interpreted.

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza con el punto de entrada de stubgen y reproduce el problema usando cm.py, el ejemplo de @asynccontextmanager del informe. Compara la salida .pyi generada para funciones y métodos generadores asíncronos y, después, ejecuta mypy sobre el stub generado. Se considera terminado cuando el stub generado para este caso pasa la comprobación de tipos sin errores y conserva la tipificación prevista del gestor de contexto.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
cli, tooling
Tipo de issue
Error
Dificultad
3/5
Tiempo estimado
1-2 días
Estado de actividad
Tranquilo
Claridad
Bien especificado
Aptitud para principiantes
72/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.