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: microsoft/pyright#4653 (comment)
Could mypy
do the same?