python / python/typeshed

maximum arity of itertools.product() is hardcoded to 10. document, increase, or print a warning?

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

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

Ngôn ngữ chính
Python
Star
5.1k
Fork
2.1k
Merge trung bình
1 ngày 19 giờ
Pull request đã merge (30 ngày)
82

Mô tả

Hi,

for reasons that I can't control, I have to support a software that calls itertools.product() with an arity greater than 10. I use mypy (currently 1.15.0) and python 3.13.1, but the problem is largely independent from the software versions.

It took me a couple of days to realize that this case is not supported, because the maximum arity for itertools.product() is controlled by 10 manually written overloads, one for each arity.
For example, the overload for product()/10 is here:

https://github.com/python/typeshed/blob/24c78b9e0dff457275092025a14387dac206f5d6/stdlib/itertools.pyi#L261-L274

The problem I faced is that the type checker (mypy 1.14.x and 1.15.x in my case), instead of clearly asserting that it could not work with arities greater than 10, spit out wrong deductions (see the example later on).

The obvious desiderata here would be not having to rely on any hardcoded overloads and support functions of arbitrary arity. I suppose this requires a more powerful type system, or checker, or both. In each case I do not expect it to happen in a short time, right?

However, it took me a couple of days to realize the existence of this limitation in the type deduction of itertools.product(), because I kept trying to find a bug in the code I have to maintain; I'd like to spare this suffering to future users.

Do you think at least one of the following is possible?

  1. find a way to cause a warning in the type checkers, so that users know that they are experiencing a limitation in the stubs/type checker and not in their code
  2. increment the number of supported overloads for itertools.product() from 10 to 15, so that the limitation is hit more rarely. I have manually altered itertools.pyi in my venv, and it makes mypy happy (and cause misery to the idealists among us)
  3. document the limitation on the maximum arity of itertools.product(), for example in https://typing.readthedocs.io/

If 2. is acceptable, I am willing to submit a PR. With enough hand holding, I could also contribute point 3, if it helps.

Thank you very much.

Example of a program that breaks badly when iterable_11 is uncommented:

from itertools import product
from typing import Literal


def f(
    iterable_01: tuple[Literal["one"]] | list[int],
    iterable_02: list[Literal[2]],
    iterable_03: list[Literal[3]],
    iterable_04: list[Literal[4]],
    iterable_05: list[Literal[5]],
    iterable_06: list[Literal[6]],
    iterable_07: list[Literal[7]],
    iterable_08: list[Literal[8]],
    iterable_09: list[Literal[9]],
    iterable_10: list[Literal[10]] | tuple[None, Literal[10]],
    # iterable_11: list[Literal[11]],
) -> None:
    for (
        elem_01,
        elem_02,
        elem_03,
        elem_04,
        elem_05,
        elem_06,
        elem_07,
        elem_08,
        elem_09,
        elem_10,
        # elem_11,
    ) in product(
        iterable_01,
        iterable_02,
        iterable_03,
        iterable_04,
        iterable_05,
        iterable_06,
        iterable_07,
        iterable_08,
        iterable_09,
        iterable_10,
        # iterable_11,
    ):
        reveal_type(elem_01)
        reveal_type(elem_02)
        reveal_type(elem_03)
        reveal_type(elem_04)
        reveal_type(elem_05)
        reveal_type(elem_06)
        reveal_type(elem_07)
        reveal_type(elem_08)
        reveal_type(elem_09)
        reveal_type(elem_10)

Type checking with 10 arguments and correct type deduction:

$ mypy itertools_product.py 
itertools_product.py:43: note: Revealed type is "Literal['one']"
itertools_product.py:44: note: Revealed type is "Literal[2]"
itertools_product.py:45: note: Revealed type is "Literal[3]"
itertools_product.py:46: note: Revealed type is "Literal[4]"
itertools_product.py:47: note: Revealed type is "Literal[5]"
itertools_product.py:48: note: Revealed type is "Literal[6]"
itertools_product.py:49: note: Revealed type is "Literal[7]"
itertools_product.py:50: note: Revealed type is "Literal[8]"
itertools_product.py:51: note: Revealed type is "Literal[9]"
itertools_product.py:52: note: Revealed type is "Union[Literal[10], None]"
Success: no issues found in 1 source file

Type checkng with 11 arguments and incorrect type deduction (this is random: sometimes mypy writes builtins.object, instead):

$ mypy itertools_product.py 
itertools_product.py:43: note: Revealed type is "Union[Literal['one'], builtins.int, None]" <-- wider, but wrong
itertools_product.py:44: note: Revealed type is "Union[Literal['one'], builtins.int, None]" <-- completely wrong
itertools_product.py:45: note: Revealed type is "Union[Literal['one'], builtins.int, None]" [...]
itertools_product.py:46: note: Revealed type is "Union[Literal['one'], builtins.int, None]" [...]
itertools_product.py:47: note: Revealed type is "Union[Literal['one'], builtins.int, None]" [...]
itertools_product.py:48: note: Revealed type is "Union[Literal['one'], builtins.int, None]" [...]
itertools_product.py:49: note: Revealed type is "Union[Literal['one'], builtins.int, None]" [...]
itertools_product.py:50: note: Revealed type is "Union[Literal['one'], builtins.int, None]" [...]
itertools_product.py:51: note: Revealed type is "Union[Literal['one'], builtins.int, None]" [...]
itertools_product.py:52: note: Revealed type is "Union[Literal['one'], builtins.int, None]" <-- completely wrong
Success: no issues found in 1 source file

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.

Hướng nghiên cứu

Bắt đầu với stdlib/itertools.pyi, tại phần xung quanh các overload của product() được liên kết trong issue, sau đó chạy các ví dụ được cung cấp với mười và mười một đối số bằng mypy để tái hiện sự khác biệt trong việc suy luận. Xem lại vị trí được đề cập trên typing.readthedocs.io và phần thảo luận trước khi quyết định liệu đóng góp nên mở rộng các overload, ghi lại giới hạn hay theo đuổi một cảnh báo; được xem là hoàn tất khi biện pháp được chọn đã được thống nhất và hành vi của nó được chứng minh.

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

Đánh giá

Công nghệ
python
Lĩnh vực
tooling
Loại issue
Tính năng
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
42/100

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.