Reputation: 81
I have a small function which I've typohinted, but I get a mypy error. I looked it up and found some suggestions regarding casting and adding assertion but they don't help either.
I'm using mypy==0.812
and Python 3.6. Any hints on how to fix this would help.
error: Value of type "Optional[Dict[Any, Any]]" is not indexable
This is the function:
from typing import Union
from datetime import datetime
def _get_number(my_dict: Union[dict, None], relevant_key: Union[str, None]) -> int:
if my_dict is None:
return 0
else:
# my_dict: dict = cast(dict, my_dict) # adding this didn't help with the mypy error
# assert isinstance(my_dict, dict) # adding this didn't help with the mypy error
sorted_keys = sorted(
my_dict,
key=lambda k: datetime.strptime(my_dict[k], "%H:%M").time(),
)
return sorted_keys.index(relevant_key)
Upvotes: 3
Views: 8979
Reputation: 1326
While @kaya3 is correct, it quite defeats the use of a lambda function to have to specify all of this just to satisfy type checking. I would offer the alternative to just let mypy skip this line with an ignore pragma.
sorted_keys = sorted(
my_dict,
key=lambda k: datetime.strptime(my_dict[k], "%H:%M").time(),
) #type: ignore
Upvotes: 0
Reputation: 51102
The problem is that although my_dict
is known to be a dictionary where the lambda is declared, MyPy is not smart enough to know it will still be a dictionary when the lambda is called. In the general case, MyPy is correct to label this as an error:
def test(d: Optional[dict]) -> None:
if d is not None:
# d is definitely a dict where the lambda is declared
f = lambda: print(d['foo'])
d = None
# now d is None when the lambda is called
f()
The difference between your code and this example is that there is no opportunity for my_dict
to become None
in between the lambda being declared and it being called, because sorted
calls the lambda immediately and then discards it. But MyPy doesn't know that, so it conservatively labels your code with the same error.
The solution is to use a variable of type dict
instead of Optional[dict]
. You can achieve this simply by declaring a new variable like my_actual_dict: dict = my_dict
just after checking that my_dict
isn't None
, and then use my_actual_dict
in the lambda. Since my_actual_dict
has the static type dict
, MyPy knows it can't be assigned the value None
after the lambda is declared.
Upvotes: 4