Description
This is an idea for a new type system feature that can help more accurately type some decorators and wrapper functions, like @async()
from https://github.com/quora/asynq.
I'd like to see something like this work:
from mypy_extensions import ArgumentsVar
from typing import TypeVar, Awaitable
_ArgsT = ArgumentsVar('_ArgsT')
_RetT = TypeVar('_RetT')
def make_awaitable(fn: Callable[_ArgsT, _RetT]) -> Callable[_ArgsT, Awaitable[_RetT]]:
async def wrapper(**args: _ArgsT, **kwargs: _ArgsT) -> Awaitable[_RetT]:
result = fn(*args, **kwargs)
return result
return wrapper
@make_awaitable
def f(x: int, y: str) -> int:
return 3
reveal_type(f(1, 'x')) # Awaitable[int]
f(1, 1) # error, second argument must be str
f(1, z=3) # error, z is not a valid kwarg
Having a function's args and kwargs annotated with an ArgumentsVar
would mean that it takes the arguments that the ArgumentsVar
resolves to. As an extension, we could also make something like def f(x: int, *args: _ArgsT, **kwargs: _ArgsT) -> _T: ...
work to indicate that a function takes an argument called x
plus the arguments specified in _ArgsT
.
This could also improve some types in the standard library. For example, the annotations for functools.singledispatch
currently don't check function arguments. With ArgumentsVar, it could be typed as follows:
_T = TypeVar('_T')
_ArgsT = ArgumentsVar('_ArgsT')
class _SingleDispatchCallable(Generic[_ArgsT, _T]):
registry = ... # type: Mapping[Any, Callable[_ArgsT, _T]]
def dispatch(self, cls: Any) -> Callable[_ArgsT, _T]: ...
@overload
def register(self, cls: Any) -> Callable[[Callable[_ArgsT, _T]], Callable[_ArgsT, _T]]: ...
@overload
def register(self, cls: Any, func: Callable[_ArgsT, _T]) -> Callable[_ArgsT, _T]: ...
def _clear_cache(self) -> None: ...
def __call__(self, *args: _ArgsT, **kwargs: _ArgsT) -> _T: ...
def singledispatch(func: Callable[_ArgsT, _T]) -> _SingleDispatchCallable[_ArgsT, _T]: ...
This kind of thing has come up before, but I'm not sure a concrete solution has been proposed. I'll try to implement this to see how well it works.