Consider the following code:
#!/usr/bin/env python3
import time
from typing import Dict, Union, Any, cast, Callable
some_variable = {'aaa': '123', 'zzz': 1} # type: Dict[str, Union[str, int]]
# ensure that some_variable['zzz'] is an int
some_variable['zzz'] = int(some_variable['zzz'])
sleep_time = some_variable['zzz'] # type: int
time.sleep(sleep_time)
Clearly, by the time sleep_time is defined, the type of some_variable['zzz'] is an int.
Yet, mypy gives an error: Incompatible types in assignment (expression has type "Union[str, int]", variable has type "int").
My questions is: how to tell mypy that the type is int at that point in the code? And better: how to tell mypy that the type is some complex data structure at that point in the code?
Notes:
As far as I know, there is no way to tell mypy about the data structure for a specific key in
dictduring initialization of the dict, so I like to tell mypy about the structure when I process it. That's what I try to do withsleep_time = some_variable['zzz'] # type: int.assert isinstance(some_variable['zzz'], int)does suppress the error. Unfortunately, I can't useisinstance, since the actual data type in my code is not an int, but more complex data structure. Adding a linesome_variable['zzz'] = cast(int, some_variable['zzz'])orsome_variable['zzz'] = int(some_variable['zzz'])does not seem to make a difference to mypy. That's too bad, as cast() can take complex data structures, and I can define a complex data structure as the output of a type coercion function.To my surprise,
some_variable = {'aaa': '123', 'zzz': 1} # type: Dict[str, Any](thus withAnyinstead ofUnion[str,int]) silences any errors by mypy.Adding
type: intto the linesome_variable['zzz'] = int(some_variable['zzz'])gives an error:Unexpected type declaration.FYI, my actual codes is more akin to the following, where
some_variableis read from file, but with more complex normalisation functions thanstr.lower()andint().
mappers = {
'aaa': str.lower,
'zzz': int
} # type: Dict[str, Callable[[Any], Union[str, int]]]
defaults = {
'aaa': '',
'zzz': 2
} # type: Dict[str, Union[str, int]]
for key, value in some_variable.items():
try:
some_variable[key] = mappers[key](value)
except Exception:
some_variable[key] = defaults[key]