How to tell mypy about a complex type for a specific item in a dict?

Viewed 452

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:

  1. As far as I know, there is no way to tell mypy about the data structure for a specific key in dict during initialization of the dict, so I like to tell mypy about the structure when I process it. That's what I try to do with sleep_time = some_variable['zzz'] # type: int.

  2. assert isinstance(some_variable['zzz'], int) does suppress the error. Unfortunately, I can't use isinstance, since the actual data type in my code is not an int, but more complex data structure. Adding a line some_variable['zzz'] = cast(int, some_variable['zzz']) or some_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.

  3. To my surprise, some_variable = {'aaa': '123', 'zzz': 1} # type: Dict[str, Any] (thus with Any instead of Union[str,int]) silences any errors by mypy.

  4. Adding type: int to the line some_variable['zzz'] = int(some_variable['zzz']) gives an error: Unexpected type declaration.

  5. FYI, my actual codes is more akin to the following, where some_variable is read from file, but with more complex normalisation functions than str.lower() and int().

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]
0 Answers
Related