python / python/mypy

Unsatisfyable descriptors: mark defintion, not usage

Open
#9,373 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature topic-descriptors
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No source files or tests are named. Start by reproducing the descriptor example with mypy 0.782 and trace how descriptor types are checked at declaration versus access. Done means the incompatible descriptor is reported at its definition, with an actionable diagnostic, rather than only at ints.c.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.