Wrong revealed type of float/int multiplied/divided by sum(Iterable[complex]).
For the code below (Python 3.7.1) mypy 0.650 improperly reveals types of expressions: (float/int multiplied/divided by the sum(arg)), where arg is Iterable[complex] and generates false positive errors for the type of the first argument of the sum (they are in comments). Attempt to explicitly define 'start' parameter does not help. There are no problems with locally defined function f2 with similar signature.
Additional question is: what does mean '' in "Revealed type is 'builtins.complex'" in the line 13?
from typing import Iterable, TYPE_CHECKING, TypeVar
_TC = TypeVar('_TC', int, float, complex)
def f1(arg: Iterable[complex]) -> complex:
if TYPE_CHECKING:
reveal_type(f2(arg)) # Revealed type is 'builtins.complex' Ok.
reveal_type(1/f2(arg)) # Revealed type is 'builtins.complex' Ok.
reveal_type(1*f2(arg)) # Revealed type is 'builtins.complex' Ok.
reveal_type(sum(arg)) # Revealed type is 'builtins.complex*' <- What does mean '*' at the end?
reveal_type(1/sum(arg)) # Revealed type is 'builtins.float' ???
# Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[int]" ???
reveal_type(1*sum(arg)) # Revealed type is 'builtins.int' ???
# Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[int]" ???
reveal_type(1.0/sum(arg)) # Revealed type is 'builtins.float' ???
# Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[float]" ???
reveal_type(1.0*sum(arg)) # Revealed type is 'builtins.float' ???
# Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[float]" ???
reveal_type(1/sum(arg, start=complex(0.0))) # Revealed type is 'builtins.float' ???
# Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[int]" ???
reveal_type(complex(1)/sum(arg)) # Revealed type is 'builtins.complex' <- workaround
reveal_type(1/complex(sum(arg))) # Revealed type is 'builtins.complex' <- workaround
return 1/sum(arg) # error: Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[int]"
def f2(arg: Iterable[_TC]) -> _TC:
return 1/next(iter(arg))
if __name__ == '__main__':
a = [1.0, 2.0+3.0j]
print(f1(a))
The * means it's an inferred type, not an explicitly specified type. It doesn't really matter unless you're interested in mypy internals.
This is another example of the situation where mypy is too eager about return/outer type context. Mypy uses the external context first, in particular, in this example int.__mul__ annotated as (int) -> int, sets the int context for sum(...), so the type variable _T is inferred as int. Therefor you see a weird error like "Iterable[int]" expected. Since this is a well known problem, mypy special-cases functions that return a plain type variable (like f2() in your example). But the crux is that sum() is annotated in typeshed as returning Union[_T, int], so that special-casing doesn't apply to it, and you see the bug.
Possible short term solution is to annotate sum() as just returning _T, but the only long term solution is to use "single bin inference".
See also https://github.com/python/mypy/issues/5971
Possible short term solution is to annotate
sum()as just returning_T, but the only long term solution is to use "single bin inference".
How would I go about annotating sum()?
Cheers
This issue can be closed.
Everything about sum(...) works in the example above with the mypy 0.960 while a version 0.950 still was with same errors.
The only reported error remains in the function f2() but it is an incorrectly typed function, because 1 / 1 is a float not an int. If the the "int" is removed from the second line: _TC = TypeVar('_TC', float, complex) then everything works also with int, float and complex:
reveal_type(f2([1])) # Revealed type is "builtins.float"
@hauntsaninja This issue can be closed similarly to #8814 that you closed yesterday.