Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

can't compose @future_safe coroutines that specify picky exceptions

Đang mở
#2,080 3 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức phù hợp với người mới
32/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Đình trệ
Công nghệ
python
Lĩnh vực
devtools

Hướng nghiên cứu

Bắt đầu bằng cách chạy ví dụ mre.py được cung cấp với returns[compatible-mypy]==0.25.0 và mypy, sau đó kiểm tra hành vi kiểu của future_safe và FutureResult.bind. Hoàn thành khi hai coroutine kết hợp được với nhau mà không có lỗi kiểu, đồng thời vẫn giữ các trường hợp ConnectionError và ZeroDivisionError riêng biệt.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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.

Ngôn ngữ chính
Python
Star
4.4k
Fork
154
Merge trung bình
3 giờ 5 phút
Pull request đã merge (30 ngày)
22

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của dry-python/returns

Tất cả issue của dry-python/returns

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.