I have something like the following:
from typing import TypeVar, Callable, Generic, Type, Union, Optional
T = TypeVar("T")
V = TypeVar("V")
class DescClass(Generic[T, V]):
"""A descriptor."""
def __init__(self, func: Callable[[T], V]) -> None:
self.func = func
def __get__(self, instance: Optional[T], owner: Type[T]) -> Callable[[], V]:
return self.func.__get__(instance, owner)
class C:
@DescClass
def f(self): ...
...for which Mypy will return this error:
test.py:12: error: "Callable[[T], Any]" has no attribute "__get__"
What is the canonical way to specify the type for func
, so that Mypy understands it is a descriptor (and thus always has a __get__
)?
Update: it's a bit humorous that "descriptor" has no hits when searching the Mypy help.
This appears to work fine on modern Python and modern mypy:
from typing import (
TypeVar,
Callable,
Generic,
Type,
Optional,
cast,
Protocol
)
T_contra = TypeVar("T_contra", contravariant=True)
V = TypeVar("V")
P_co = TypeVar("P_co", covariant=True)
class DescriptorProto(Protocol[P_co, T_contra]):
def __get__(
self,
instance: Optional[T_contra],
owner: Type[T_contra]
) -> P_co:
...
FuncType = DescriptorProto[Callable[[], V], T_contra]
class DescClass(Generic[T_contra, V]):
"""A descriptor."""
def __init__(self, func: Callable[[T_contra], V]) -> None:
self.func = cast(FuncType[V, T_contra], func)
def __get__(
self,
instance: Optional[T_contra],
owner: Type[T_contra]
) -> Callable[[], V]:
return self.func.__get__(instance, owner)
class C:
@DescClass
def f(self) -> None: ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With