Description
🚀 Improvement
After #2266 merged, mypy is understanding and checking the usage of the descriptor protocol. However, the validity of the types of a descriptor are only checked when the descriptor is used, not when it is declared: So you can define a descriptor that can never be accessed, as access to the descriptor will always result in a type error (see example below)
Versions
mypy 0.782
python 3.7.8
Pitch
Giving a error for unusable descriptors would help to find mistakes early on.
Furthermore, with the current error message when using such a descriptor, it is quite hard find the source of the problem, which is the descriptor instance itself, not the code where the descriptor is accessed.
Example
S = TypeVar('S', bound='Spec')
from __future__ import annotations
from typing import TypeVar, Type, overload, Generic
S = TypeVar("S", bound='Spec')
class Spec:
def __init__(self, name):
self.name = name
@overload
def __get__(self: S, obj: None, typ: Type[Service[S]]) -> S: ...
@overload
def __get__(self: S, obj: Service[S], typ: Type[Service[S]]) -> Service[S]: ...
def __get__(self, obj, typ):
if obj is None:
self
else:
service.push(S)
return obj.service
class Int(Spec):
pass
class String(Spec):
pass
class Service(Generic[S]):
def push(self, S):
...
class IntService(Service[Int]):
a = Int('a')
b = Int('b')
c = String('c') # offending descriptor: obj in __get__ will be a Service[Int], but Service[String] is expected for String
def usage(ints: IntService):
ints.a
ints.c # only this line will cause a typing issue and it has no indication to the offending definition 4 lines abouve
Only the last line currently is reporting an error: Argument 1 to "__get__" of "Spec" has incompatible type "IntService"; expected "Service[String]"
, the offending descriptor is silently ignored and it is quite hard to find that line from this error.