Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

can't compose @future_safe coroutines that specify picky exceptions

Abierto
#2,080 3 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
5/5
Tiempo estimado
Más de una semana
Aptitud para principiantes
32/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Estancado
Stack tecnológico
python
Área
devtools

Línea de trabajo

Empieza ejecutando el ejemplo mre.py proporcionado con returns[compatible-mypy]==0.25.0 y mypy, y después inspecciona el comportamiento de tipado de future_safe y FutureResult.bind. Se considera terminado cuando las dos corrutinas se componen sin un error de tipos y conservan sus casos independientes de ConnectionError y ZeroDivisionError.

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

Descripción

Given coroutines coro1, coro2:

@future_safe(exceptions=(ConnectionError,))
async def coro1(c: int | None) -> int:
    if c is None:
        raise ConnectionError("not connected")
    await asyncio.sleep(0)  # emulate I/O
    return c


@future_safe(exceptions=(ZeroDivisionError,))
async def coro2(n: int) -> float:
    await asyncio.sleep(0)  # emulate I/O
    return 1 / n

I want to combine them via bind: coro1(c).bind(coro2). It results in type error:

$ uvx --with 'returns[compatible-mypy]==0.25.0' mypy mre.py; ./mre.py
mre.py:30: error: Argument 1 to "bind" of "FutureResult" has incompatible type "Callable[[int], FutureResult[float, ZeroDivisionError]]"; expected "Callable[[int], KindN[FutureResult[Any, Any], float, ConnectionError, Any]]"  [arg-type]

where mre.py:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
#     "returns >=0.25.0",
# ]
# ///
from typing import assert_never
from returns.result import Success, Failure
from returns.io import IOSuccess, IOFailure
from returns.future import future_safe


@future_safe(exceptions=(ConnectionError,))
async def coro1(c: int | None) -> int:
    if c is None:
        raise ConnectionError("not connected")
    await asyncio.sleep(0)  # emulate I/O
    return c


@future_safe(exceptions=(ZeroDivisionError,))
async def coro2(n: int) -> float:
    await asyncio.sleep(0)  # emulate I/O
    return 1 / n


async def run() -> None:
    for c in [2, 0, None]:
        match await coro1(c).bind(coro2):
            case IOSuccess(Success(r)):
                assert r == 1 / 2, r
            case IOFailure(Failure(ZeroDivisionError(args=(msg,)))):
                assert msg == "division by zero", msg
            case IOFailure(Failure(ConnectionError(args=(msg,)))):
                assert msg == "not connected", msg
            case _ as unreachable:
                assert_never(unreachable)  # type: ignore[arg-type]


if __name__ == "__main__":
    import asyncio

    asyncio.run(run())

If picky exceptions are removed:

@future_safe
async def coro1(c: int | None) -> int: ...

@future_safe
async def coro2(n: int) -> float: ...

I get the desired behavior that coroutines are composed without type errors but these declarations catch too much.

Lenguaje dominante
Python
Estrellas
4.4k
Forks
154
Merge medio
3 h 5 min
PR fusionados (30 d)
22

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.

Más de dry-python/returns

Todos los issues de dry-python/returns

Issues similares

Más issues de Python

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.