Recently, I've been exploring the type
hints functionality in Python.
The other day, I ran across what I *think* is a bug (already known) in
mypy.

Here is a minimal working example of the issue I came across:

`from fractions import Fraction`

`my_value = 1 + sum([Fraction(k + 1, 5 ** k) for k in range(5)])`

`print(f"The result is {my_value}.")`

This program runs as you would expect.

`python example.py`

The result is 64/25.

However, the type-check fails!

`mypy example.py`

example.py:3: error: List comprehension has incompatible type List[Fraction]; expected List[int] Found 1 error in 1 file (checked 1 source file)

At this point, I was really confused, but after searching for the error, I came across an
issue on GitHub that reported this. In the
discussion, someone explained that the problem is that mypy isn't taking into account the
`__radd__`

method.
(In general, `x + y`

is shorthand for `x.__add__(y)`

. However, if `x.__add__`

doesn't know
how to deal with `y`

, then Python tries to use `y.__radd__(x)`

instead.)
Following the example in the discussion there, I modified the program as follows:

`my_value = Fraction(1) + sum([Fraction(k + 1, 5 ** k) for k in range(5)])`

The modified version type-checked okay.

At this point, I decided to come up with what my doctoral advisor would call a "Toy Example":

`from __future__ import annotations `

`# Allow self-referential type hints`

`from typing import Union`

`class A:`

` def __init__(self: A, value: int) -> None:`

` self.value = value`

` def __repr__(self: A) -> str:`

` return f"{self.__class__.__name__}({self.value!r})"`

` def __add__(self: A, other: Union[A, int]) -> A:`

` print(f"Calling {self!r}.__add__({other!r})")`

` if isinstance(other, A):`

` return self.__class__(self.value + other.value)`

` elif isinstance(other, int):`

` return self.__class__(self.value + other)`

` else:`

` return NotImplemented`

` def __radd__(self: A, other: int) -> A:`

` print(f"Calling {self!r}.__radd__({other!r})")`

` if isinstance(other, int):`

` return self.__class__(self.value + other)`

` else:`

` return NotImplemented`

`if __name__ == "__main__":`

` values_to_sum = [A(k) for k in range(1, 5)]`

` print(f"Computation #1: {sum(values_to_sum)=}")`

` print(f"Computation #2: {A(5) + sum(values_to_sum)=}")`

` print(f"Computation #3: {5 + sum(values_to_sum)=}")`

` print(f"Computation #4: {sum(values_to_sum) + A(5)=}")`

` print(f"Computation #5: {sum(values_to_sum) + 5=}")`

` print(f"Computation #6: {A(5) + A(6)=}")`

` print(f"Computation #7 {5 + A(6)=}")`

` print(f"Computation #8 {A(5) + 6=}")`

Then it executes just fine, but `mypy`

is upset about line 33, in which
`A(10).__radd__(5)`

is called. (In the output below, the `Calling ...`

text is output
before the result of the computation.)

`python3 example.py`

Calling A(1).__radd__(0) Calling A(1).__add__(A(2)) Calling A(3).__add__(A(3)) Calling A(6).__add__(A(4)) Computation #1: sum(values_to_sum)=A(10) Calling A(1).__radd__(0) Calling A(1).__add__(A(2)) Calling A(3).__add__(A(3)) Calling A(6).__add__(A(4)) Calling A(5).__add__(A(10)) Computation #2: A(5) + sum(values_to_sum)=A(15) Calling A(1).__radd__(0) Calling A(1).__add__(A(2)) Calling A(3).__add__(A(3)) Calling A(6).__add__(A(4)) Calling A(10).__radd__(5) Computation #3: 5 + sum(values_to_sum)=A(15) Calling A(1).__radd__(0) Calling A(1).__add__(A(2)) Calling A(3).__add__(A(3)) Calling A(6).__add__(A(4)) Calling A(10).__add__(A(5)) Computation #4: sum(values_to_sum) + A(5)=A(15) Calling A(1).__radd__(0) Calling A(1).__add__(A(2)) Calling A(3).__add__(A(3)) Calling A(6).__add__(A(4)) Calling A(10).__add__(5) Computation #5: sum(values_to_sum) + 5=A(15) Calling A(5).__add__(A(6)) Computation #6: A(5) + A(6)=A(11) Calling A(6).__radd__(5) Computation #7 5 + A(6)=A(11) Calling A(5).__add__(6) Computation #8 A(5) + 6=A(11)

`mypy example.py`

example.py:33: error: Argument 1 to "sum" has incompatible type "List[A]"; expected "Iterable[int]" Found 1 error in 1 file (checked 1 source file)

If you remove line 33 in the script (the one that evaluates `5 + sum(values_to_sum)`

),
then mypy has no problem!

`mypy example.py`

Success: no issues found in 1 source file

Note that line 33 isn't the only place that `__radd__`

ends up being called. It's called
every time `sum(values_to_sum)`

is evaluated (since you start each sum with a value of the
integer 0). It's also called in line 37, in the computation of `5 + A(6)`

. These other
invocations of `__radd__`

do not mess up mypy. It's only messed up when you `__radd__`

the
result of a `sum`

.