python / python/mypy

Type inference on `owner` argument to `__set_name__`

Abierto
#16,796 0 comentarios 1 reacción 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

feature
Lenguaje dominante
Python
Estrellas
20.6k
Forks
3.3k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

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

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comience con el ejemplo del descriptor y la inferencia solicitada del argumento owner para set_name; en el issue no se identifican archivos de implementación ni pruebas. Revise después los issues relacionados de Mypy, 10246 y 8057, y determine cómo debería tipar la inferencia en el cuerpo de la clase la lambda del validador y cómo deberían rechazarse las implementaciones incorrectas.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
devtools
Tipo de issue
Nueva funcionalidad
Dificultad
5/5
Tiempo estimado
Más de una semana
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
30/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.