python / python/mypy

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

Ouverte
#14,726 0 commentaires 1 réaction 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

feature
Langage dominant
Python
Étoiles
20.6k
Forks
3.3k
Métriques de merge des PR
Métriques de PR en attente

Description

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?

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par reproduire l’exemple Base/Sub fourni avec mypy 1.0.0 et comparez les diagnostics pour foo et goo avec le comportement attendu de Never. Le travail est terminé lorsqu’une méthode de sous-classe sans argument peut être déclarée comme non appelable sans type: ignore et que la redéfinition de goo est traitée de manière cohérente avec la règle de substitution de Liskov.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
compilers
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
30/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.