python / python/mypy

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

Offen
#14,726 0 Kommentare 1 Reaktion 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

feature
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

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?

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne damit, das bereitgestellte Base/Sub-Beispiel mit mypy 1.0.0 zu reproduzieren und die Diagnosen für foo und goo mit dem beabsichtigten Never-Verhalten zu vergleichen. Die Arbeit ist abgeschlossen, wenn eine parameterlose Methode einer Unterklasse als nicht aufrufbar deklariert werden kann, ohne ein type: ignore zu verwenden, und das goo-Override konsistent mit der Liskov-Substitutionsregel behandelt wird.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
compilers
Issue-Typ
Feature
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
30/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.