I am trying to add type hints to one of my codes. I am using mypy to check that the types declared in my code are consistent. However, I found the following situation that I don't know how to solve:
I have a rather complicated dictionary, which in general has type
dict[tuple[tuple[int, int], str], str]
However, there are a few cases where the int
values could be missing and be None. But at least one of the two will be there. Therefore, I have declared the dict as
dict[
tuple[
Union[
tuple[Optional[int], int],
tuple[int, Optional[int]]],
str],
str]
However, this doesn't seem to work well with mypy, since I have the following code:
for (int1, int2), str in dict:
if int1 is None:
int2 + 3
else:
...
and mypy is giving me the following output for the line "int2 + 3":
error: Unsupported operand types for + ("None" and "int") [operator]
note: Left operand is of type "int | None"
I know the code is working since it is not possible that both int1 and int2 are None simultaneously. Thus, since the line will run only when int1 is None, then int2 is guaranteed to be an int. Is my type hint wrong? Or simply mypy is not smart enough to realise this?
As far as I can tell, neither mypy
nor PyRight can assign a static type to int1
and int2
that distinguishes between the two sides of the union. As far is it goes, both can be int|None
, and therefore knowing that int1
is None
does not imply to the checker that int2
is not None
. (Roughly speaking, the types of int1
and int2
are not independent of each other, and you need to assign the pair some kind of "joint" type.)
You're going to have to help the type checker out, and expicitly assert that int2
has type int
when you know that to be the case.
for (int1, int2), str in dict:
if int1 is None:
assert int2 is not None
int2 + 3
else:
...