Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unsatisfyable descriptors: mark defintion, not usage #9373

Open
wabu opened this issue Aug 28, 2020 · 0 comments
Open

Unsatisfyable descriptors: mark defintion, not usage #9373

wabu opened this issue Aug 28, 2020 · 0 comments
Labels
feature topic-descriptors Properties, class vs. instance attributes

Comments

@wabu
Copy link

wabu commented Aug 28, 2020

馃殌 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.

@wabu wabu added the feature label Aug 28, 2020
@JelleZijlstra JelleZijlstra added the topic-descriptors Properties, class vs. instance attributes label Mar 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature topic-descriptors Properties, class vs. instance attributes
Projects
None yet
Development

No branches or pull requests

2 participants