Open
Description
Bug Report
partial
support is too fragile and easy to fool.
To Reproduce
import typing as t
from functools import partial
# 1.
# uncomment this to get type error
# partial(lambda x, y: x + y, 10)()
# 2.
# But this silly little thing passes type-check
silly: t.Callable[[], int] = partial(lambda x, y: x + y, 10)
silly()
Expected Behavior
Fail to coerce partial into incompatible callable type.
Actual Behavior
Success: no issues found in 1 source file
Your Environment
- Mypy version used: master
- Mypy command-line flags: no
- Mypy configuration options from
mypy.ini
(and other config files): - Python version used: 3.12
Looks like we carry information about needed arguments somewhere anyways, since 1
fails type check due to not enough arguments, so why we allow to coerce that partial into incompatible callable?
Perhaps this is due to this definition of partial:
def __call__(self, /, *args: Any, **kwargs: Any) -> _T: ...
But, for example, pyright
takes that into account and fails as expected:
[nix-shell:/tmp]$ pyright issue.py
/tmp/issue.py
/tmp/issue.py:10:30 - error: Expression of type "partial[Unknown]" is incompatible with declared type "() -> int"
Type "partial[Unknown]" is incompatible with type "() -> int"
Extra parameter "y" (reportAssignmentType)
1 error, 0 warnings, 0 informations
I think it worth fixing, since we support partial
and it is useful to rely on that support. It can be fixed, for example, as viewing partial
result internally not as partial[int]
type, but as something like
class FakePartial(Protocol[P, Ret]):
@property
def args(self) -> tuple[Any, ...]: ...
@property
def keywords(self) -> dict[any, ...]: ...
@property
def func(self) -> t.Callable[..., Ret]: ...
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Ret: ...