Generic callback protocols break with kwargs
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
I'm getting an unexpected error when using callback protocols with kwargs
Normal callback with no args or kwargs works fine:
from typing import *
T1 = TypeVar('T1')
T2 = TypeVar('T2')
T_contra = TypeVar('T_contra', contravariant=True)
T_co = TypeVar('T_co', covariant=True)
class Callback(Protocol[T_contra, T_co]):
def __call__(self, __element: T_contra) -> T_co:
pass
def applyit(func: Callback[T1, T2], y: T1) -> T2:
return func(y)
def callback(x: str) -> int:
pass
applyit(callback, 'foo') # OK!
callback with args works fine:
from typing import *
T1 = TypeVar('T1')
T2 = TypeVar('T2')
T_contra = TypeVar('T_contra', contravariant=True)
T_co = TypeVar('T_co', covariant=True)
class CallbackWithArgs(Protocol[T_contra, T_co]):
def __call__(self, __element: T_contra, *args: Any) -> T_co:
pass
def applyit_with_args(func: CallbackWithArgs[T1, T2], y: T1) -> T2:
return func(y)
def callback_with_args(x: str, *args: Any) -> int:
pass
applyit_with_args(callback_with_args, 'foo') # OK!
But the same thing with kwargs produces an error:
from typing import *
T1 = TypeVar('T1')
T2 = TypeVar('T2')
T_contra = TypeVar('T_contra', contravariant=True)
T_co = TypeVar('T_co', covariant=True)
class CallbackWithKwargs(Protocol[T_contra, T_co]):
def __call__(self, __element: T_contra, **kwargs: Any) -> T_co:
pass
def applyit_with_kwargs(func: CallbackWithKwargs[T1, T2], y: T1) -> T2:
return func(y)
def callback_with_kwargs(x: str, **kwargs: Any) -> int:
pass
# Argument 1 to "applyit_with_kwargs" has incompatible type "Callable[[str, KwArg(Any)], int]"; expected "CallbackWithKwargs[str, <nothing>]"
applyit_with_kwargs(callback_with_kwargs, 'foo') # Error!
Perhaps this is expected behavior and I'm just overlooking some subtle interplay between the args in the last case, but it seems like a bug.
mypy 0.720
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Run the supplied callback protocol reproducer with the reported mypy 0.720 behavior, comparing the no-argument, *args, and **kwargs cases. Trace the type inference and callback compatibility paths responsible for the diagnostic, then add a regression test showing that the kwargs callback is accepted without losing the return type.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100