I've been struggling to write "varadic" argument lists type definitions.
for example, giving types to:
def foo(fn, *args):
return fn(*args)
the best I've been able to do is using a suggestion from here:
from typing import overload, Callable, TypeVar
A = TypeVar('A')
B = TypeVar('B')
C = TypeVar('C')
R = TypeVar('R')
@overload
def foo(fn: Callable[[A], R], a: A) -> R: ...
@overload
def foo(fn: Callable[[A, B], R], a: A, b: B) -> R: ...
@overload
def foo(fn: Callable[[A, B, C], R], a: A, b: B, c: C) -> R: ...
def foo(fn, *args):
return fn(*args)
which mostly does the right thing… for example, given:
def bar(i: int, j: int) -> None:
print(i)
the following succeeds:
foo(bar, 10, 12)
while these fail:
foo(bar, 10)
foo(bar, 10, 'a')
foo(bar, 10, 12) + 1
but if I check with mypy --strict
I get:
test.py:15: error: Function is missing a type annotation
(which is saying that the final foo
definition doesn't have any types itself)
I can redefine foo
to be:
def foo(fn: Callable[..., R], *args: Any) -> R:
return fn(*args)
but then when I run mypy --strict
I get:
test.py:15: error: Overloaded function implementation does not accept all possible arguments of signature 1
test.py:15: error: Overloaded function implementation does not accept all possible arguments of signature 2
test.py:15: error: Overloaded function implementation does not accept all possible arguments of signature 3
which I don't really understand.
if anyone can suggest a better way of giving types to this sort of function it would be greatly appreciated! if I could also do this without listing lots of overload
s that would be nice, the real definitions also have a few "keyword only" arguments that would be nice not to have to repeat each time