Open
Description
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.
Metadata
Metadata
Assignees
Labels
No labels