Description
Bug Report
If you declare an attribute on a dataclass to be Callable
, Mypy assumes that its __get__
will not be called, even on a default attribute. But this is only true if the default is a FunctionType
, not some other type of callable.
Similarly, the inverse is true: an abstract type (such as a callable Protocol
) will tell mypy that __get__
will be called, even though if the concrete default value is a FunctionType
, it won't be.
Specifically, the following program contains 2 type errors, but MyPy does not think so:
To Reproduce
from __future__ import annotations
from typing import Callable, Protocol, ParamSpec, TypeVar, Generic
from dataclasses import dataclass
def f() -> None:
print("hello world")
def f2(self: object) -> None:
print("bound self", self)
P = ParamSpec("P")
T = TypeVar("T")
R = TypeVar("R", covariant=True)
T_con = TypeVar("T_con", contravariant=True)
class BindableMethod(Protocol[T_con, R]):
def __get__(self, instance: T_con, owner: None | type[object]) -> Callable[[], R]:
...
def __call__(me, self: T_con) -> R:
...
class UnboundNonFunction(Generic[P, R]):
def __call__(self) -> int:
print("unbound")
return 3
def __get__(self, instance: object, owner: type | None) -> BoundNonFunction:
print("binding", instance, owner)
return BoundNonFunction(instance)
@dataclass(frozen=True)
class BoundNonFunction:
instance: object
def __call__(self) -> str:
print("bound", self.instance)
return "wat"
@dataclass
class FuncHolder():
func: Callable[[], None] = f
func2: BindableMethod[FuncHolder, None] = f2
func3: Callable[[], int] = UnboundNonFunction()
FuncHolder().func()
try:
FuncHolder().func2()
except Exception as e:
print("whoops", str(e))
try:
print(FuncHolder().func3() + 4)
except Exception as e:
print("whoops 2", str(e))
https://mypy-play.net/?mypy=latest&python=3.11&gist=1ac4e7c090774489207dfbc737de2d61
Expected Behavior
I would expect runtime and type-time behavior to be consistent here. Specifically I just don't expect __get__
to be called on things with a Callable
type.
Actual Behavior
Mypy succeeds, rather than reporting the type errors.
Your Environment
- Mypy version used: mypy 1.1.1 (compiled: yes)
- Mypy command-line flags: none
- Mypy configuration options from
mypy.ini
(and other config files): none - Python version used: 3.11.2 (python.org, macOS, aarch64)