Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

type safety (mypy) for function parameters when using *args

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?

like image 861
Tobias Hermann Avatar asked Aug 23 '26 19:08

Tobias Hermann


1 Answers

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]"
like image 76
Tobias Hermann Avatar answered Aug 25 '26 09:08

Tobias Hermann