python / python/mypy

Type inference on `owner` argument to `__set_name__`

Aperta
#16,796 0 commenti 1 reazione 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

feature
Lingua principale
Python
Stelle
20.6k
Fork
3.3k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

Because of the circumstances under which __set_name__ is invoked, it should be possible to perform type inference on its owner argument, in a way which could be used to statically typecheck other components of a descriptor.

As a brief motivating example, below is a sketch of descriptor for a validated mutable attribute of integer type:


from __future__ import annotations
from typing import Any, Generic, Protocol, Self, Type, TypeVar, cast, overload

InstanceT = TypeVar("InstanceT")
InstanceT_contra = TypeVar("InstanceT_contra", contravariant=True)

class Validator(Protocol[InstanceT_contra]):

    def __call__(self, instance: InstanceT_contra, value: int, /) -> bool:
        ...

class IntAttr(Generic[InstanceT]):

    __validator: Validator[InstanceT]
    __name: str

    def __init__(self, validator: Validator[InstanceT]) -> None:
        self.__validator = validator

    def __set_name__(self, owner: Type[InstanceT], name: str) -> None:
        self.__name = name

    @overload
    def __get__(self, instance: None, _: Type[Any]) -> Self:
        ...

    @overload
    def __get__(self, instance: InstanceT, _: Type[Any]) -> int:
        ...

    def __get__(self, instance: InstanceT|None, _: Type[Any]) -> int | Self:
        if instance is None:
            return self
        return cast(int, getattr(instance, f"__{self.__name}"))

    def __set__(self, instance: InstanceT, value: int) -> None:
        if not self.__validator(instance, value):
            raise ValueError()
        setattr(instance, f"__{self.__name}", value)

class C:

    x = IntAttr(lambda self, value: self.validate(value)) # Pylance error

    def validate(self, value: int) -> bool:
        return value >= 10

In Pylance with strict typechecking rules, the definition of the x descriptor raises the following errors:

reportUnknownMemberType
  Type of "validate" is unknown 
reportUnknownLambdaType
  Return type of lambda is unknown
reportGeneralTypeIssues
  Cannot access member "validate" for type "object*"
    Member "validate" is unknown

Currently, Mypy doesn't raise any errors about the lack of lambda typing (not even for incorrect implementations, such as self.validatez(value) or self.validate(str(value))). Mypy also doesn't raise errors about incorrect lambda implementations once an explicit type hint is provided (see below), while Pylance does.
I opened a separate issue about this: https://github.com/python/mypy/issues/16797

Explicitly providing a hint for the InstanceT type removes the errors for Pylance:

class C:

    x = IntAttr["C"](lambda self, value: self.validate(value)) # Errors

    def validate(self, value: int) -> bool:
        return value >= 10

Performing inference on the owner argument to IntAttr.__set_name__ in the context of class C would ideally result in C being inferred as a value for InstanceT, allowing for static typecheking of the validator lambda function without the need for an explicit type hint.

Related issues for Mypy:

Sister issue for Pylance/Pyright: https://github.com/microsoft/pyright/issues/7039

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia con l’esempio del descriptor e con l’inferenza richiesta dell’argomento owner per set_name; nell’issue non sono identificati file di implementazione o test. Esamina poi le issue correlate di Mypy 10246 e 8057, quindi determina come l’inferenza nel corpo della classe dovrebbe tipizzare la lambda del validator e come dovrebbero essere rifiutate le implementazioni errate.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python
Ambito
devtools
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
30/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.