I am having problems with mypy.
I have this code:
func(arg1, arg2, arg3=0.0, arg4=0.0)
# type: (float, float, float, float) -> float
# do something and return float.
dict_with_other_arguments = {arg3: 0.5, arg4: 1.4}
a = func(arg1, arg2, **dict_with_other_arguments)
The problem is that mypy does not check what's in the dictionary for types, instead, I get an error like this:
error: Argument 3 to "func" has incompatible type "**Dict[str, float]"; expected "float"
Any ideas how to fix this without changing code?
Mypy is correct in flagging your function calls. The following code illustrates why:
def func(str_arg='x', float_arg=3.0):
# type: (str, float) -> None
print(str_arg, float_arg)
kwargs1 = {'float_arg': 8.0}
kwargs2 = {'str_arg': 13.0} # whoops
func(float_arg=5.0) # prints "x 5.0" -- good
func(**kwargs1) # prints "x 13.0" -- good but flagged by Mypy
func(**kwargs2) # prints "13.0 3.0" -- bad
In this example, kwargs1
and kwargs2
are both of type Dict[str, float]
. The type checker does not consider the content of the keys, only their types, so the second and third calls to func
look identical to Mypy. They must either both be errors or both be acceptable, and they can't both be acceptable since the third call violates the type system.
The only way that the type checker can be sure that you're not passing incorrect types in the dict is if all of the arguments that haven't been explicitly passed share the type of the dict's values. Note, however, that mypy will not protect you from errors caused by respecifying a keyword argument in a dict:
# This works fine:
func('x', **kwargs1)
# This is technically type safe and accepted by mypy, but at runtime raises
# `TypeError: func() got multiple values for argument 'str_arg'`:
func('x', **kwargs2)
There is some further discussion of this issue here.