python / python/mypy

How to use typing.Never to indicate a subclass method with zero arguments cannot be called?

Abierto
#14,726 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

Feature

If you have a subclass that has a method defined in the superclass, but in the subclass should never get called, you should be able to declare self to have type Never.

Pitch

Let's suppose I have a base class Base with a method foo(), and a subclass Sub that raises an Exception if foo() is called. I'd like it so that the type checker flags an error on Sub.foo(), but not Base.foo(), so I tried this:

from typing_extensions import Never


class Base:
    def __init__(self):
        pass

    def foo(self) -> None:
        print("foo")
        
    def goo(self, x: int) -> None;
        print("goo ", x)


class Sub(Base):
    def foo(self: Never) -> None:
        raise Exception("never")
    
    def goo(self, x: Never) -> None:
        raise Exception("never")


x = Sub()
x.foo()
x.goo(3)

With mypy 1.0.0 and python 3.10, I get the following:

neversub.py:16: error: The erased type of self "<nothing>" is not a supertype of its class "neversub.Sub"  [misc]
neversub.py:19: error: Argument 1 of "goo" is incompatible with supertype "Base"; supertype defines the argument type as "int"  [override]
neversub.py:19: note: This violates the Liskov substitution principle
neversub.py:19: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
neversub.py:24: error: Invalid self argument "Sub" to attribute function "foo" with type "Callable[[NoReturn], None]"  [misc]
neversub.py:25: error: Argument 1 to "goo" of "Sub" has incompatible type "int"; expected "NoReturn"  [arg-type]

The last two errors are exactly what I want. But while the first error makes sense, aside from using a # type: ignore, I'm not sure how this should be declared to avoid having to use # type: ignore. In other words, what is the right way to indicate that a method with zero parameters is not valid to call in a subclass? Secondly, shouldn't the declaration of goo be considered as not violating the Liskov substitution principle based on how typing.Never is supposed to work?

I should note that with the method goo(), since it has a required argument, I can use the Never declaration to show that this is invalid. What's not clear is how do you indicate that a method with no arguments is invalid without having to use # type: ignore ?

I think this is a valid use of Never, and Eric Traut from pyright agrees: https://github.com/microsoft/pyright/issues/4653#issuecomment-1434851320

Could mypy do the same?

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

Comienza reproduciendo el ejemplo proporcionado de Base/Sub con mypy 1.0.0 y compara los diagnósticos de foo y goo con el comportamiento previsto de Never. El trabajo estará terminado cuando un método de subclase sin argumentos pueda declararse como no invocable sin un type: ignore y la sobrescritura de goo se gestione de forma coherente con la regla de sustitución de Liskov.

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

Evaluación

Stack tecnológico
python
Área
compilers
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.