typeshed icon indicating copy to clipboard operation
typeshed copied to clipboard

Fix inaccurate `math.prod` Typing

Open max-muoto opened this issue 1 year ago • 3 comments

This PR fixes the issues detailed in https://github.com/python/typeshed/issues/11913. One of the main strategies for accommodating the fact that an empty list inherently changes the result of the return-type, is having the first overloads be that of Iterable[Never], which will match an empty iterable first. Since the typing was fairly inaccurate before, I'm presuming a lot of repos will have new typing errors as a result of this change.

Let's walk through some examples (all with Pyright) of the new behavior:

Empty list will always evaluate to 1

res = math.prod([])
reveal_type(res) # Revealed type is Literal[1]

Given an empty list, but a start, the result will always be the type of the start:

res = math.prod([], start=Decimal(1))
reveal_type(res) # Revealed type is `Decimal`

Another example, where the list is filled out:

res = math.prod([Decimal(1)], start=Decimal(1))
reveal_type(res) # Revealed type is `Decimal`

With multiple types:

res = math.prod([Decimal(1), 1, 2.23], start=Decimal(1))
# Obviously this will actually be Decimal, but not sure we can get any better than this.
reveal_type(res) # Revealed type is Decimal | int | float 

max-muoto avatar May 27 '24 01:05 max-muoto

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

github-actions[bot] avatar May 27 '24 02:05 github-actions[bot]

The test cases seem to work for Pyright, but have issues with MyPy since it seems MyPy doesn't match an empty list to list[Never], while Pyright does, for the overloading.

max-muoto avatar May 27 '24 02:05 max-muoto

This is still not perfect, but it's probably the best we can do reasonably. Consider this code:

from decimal import Decimal
from math import prod

reveal_type(prod([Decimal(1), Decimal(2)], start=3.4))

Mypy says: note: Revealed type is "Union[typing.SupportsFloat, typing.SupportsIndex] (not error) Runtime says: TypeError: unsupported operand type(s) for *: 'float' and 'decimal.Decimal

Akuli avatar May 27 '24 17:05 Akuli

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

github-actions[bot] avatar Sep 08 '24 03:09 github-actions[bot]