Type-checking the following code with mypy
:
def foo(a: str, b: float, c: int):
print(a, b, c + 1)
foo('ok', 2.2, 'bad')
reveals the invalid call too foo
with:
error: Argument 3 to "foo" has incompatible type "str"; expected "int"
Now let's say we have a wrapper function like the following:
from typing import Callable, Any
def say_hi_and_call(func: Callable[..., Any], *args):
print('Hi.')
func(*args)
and do an invalid call using it
say_hi_and_call(foo, 'ok', 2.2, 'bad')
mypy
will not report any errors, instead we will only get to know about this error at runtime:
TypeError: must be str, not int
I'd like to catch this error earlier. Is there a possibility to refine the type annotations in a way that mypy
is able to report the problem?
OK, the only solution I came up with is making the arity of the function explicit, i.e.
from typing import Any, Callable, TypeVar
A = TypeVar('A')
B = TypeVar('B')
C = TypeVar('C')
def say_hi_and_call_ternary(func: Callable[[A, B, C], Any], a: A, b: B, c: C):
print('Hi.')
func(a, b, c)
def foo(a: str, b: float, c: int):
print(a, b, c + 1)
say_hi_and_call_ternary(foo, 'ok', 2.2, 'bad')
Of course one would need a similar say_hi_and_call_unary
and say_hi_and_call_binary
etc. too.
But since I value my application not exploding in PROD over saving some LOC, I'm happy when mypy
is able to report the error, which now certainly is the case:
error: Argument 1 to "say_hi_and_call_ternary" has incompatible type "Callable[[str, float, int], Any]"; expected "Callable[[str, float, str], Any]"