Inconsistent assignability of callable with optional keywords to positional-only callback
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
Bug Report, To Reproduce, and Actual Behaviour
A callable with an optional keyword argument can be assigned directly to a positional-only callback protocol, but not assigned to a generic function taking the callback protocol as an argument.
from typing import *
class PosOnly[*Ts, R](Protocol):
def __call__(self, /, *args: *Ts) -> R: ...
def accepts_pos_only[*Ts, R](f: PosOnly[*Ts, R], /) -> PosOnly[*Ts, R]:
return f
def my_func(a: int, b: str, /, *, c: int = 8) -> None: ...
b: PosOnly[int, str, None] = my_func # OK
reveal_type(accepts_pos_only(b)) # OK; reveals `PosOnly[int, str, None]`
reveal_type(accepts_pos_only(my_func)) # Fails; reveals `PosOnly[Unpack[builtins.tuple[Never, ...]], Never]`
Expected Behavior
No errors; both reveals PosOnly[int, str, None]
Your Environment
- Mypy version used: 1.17
- Python version used: 3.12
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
Start by running the reproducer with mypy 1.17 and compare direct assignment of my_func with the generic accepts_pos_only(my_func) call. Trace callable protocol assignability and type inference for optional keyword arguments and positional-only callbacks. Done when both reveal_type calls succeed as PosOnly[int, str, None] without errors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100