Reputation: 18663
Imagine being given the following base class that you have no control over:
from typing import Optional
class A:
def foo(self, x: Optional[bool] = None) -> None:
pass
Now you want to write a subclass that merely distinguishes two different call signatures using typing.overload
without actually constraining the parameter types:
# ... import A
from typing import Literal, Optional, overload
class B(A):
@overload
def foo(self, x: Literal[True]) -> None: ...
@overload
def foo(self, x: Optional[Literal[False]] = None) -> None: ...
def foo(self, x: Optional[bool] = None) -> None:
pass
I would say the two overloaded B.foo
signatures combined fully cover the possible calls of A.foo
. I see no violation of the Liskov Substitution Principle here since the parameter types of B.foo
have not been narrowed.
Yet mypy
complains about this:
error: Signature of "foo" incompatible with supertype "A" [override]
note: Superclass:
note: def foo(self, x: Optional[bool] = ...) -> None
note: Subclass:
note: @overload
note: def foo(self, x: Literal[True]) -> None
note: @overload
note: def foo(self, x: Optional[Literal[False]] = ...) -> None
Is there something I am missing here or have I stumbled onto a limitation/bug of or mypy
?
I found this issue #14725, which appears to address the same problem, but since nobody reacted yet, I am not sure this is actually a bug. If more people here agree that it is, I can of course simply # type: ignore[override]
it for now and keep an eye on that issue, but maybe there is a good reason this is forbidden that I just don't understand.
A few other issues I found that seem vaguely related is this one: #14002, #3750
Tested on Python 3.9
-3.11
with mypy==1.1.1
.
For what it's worth, the PyCharm type checker also complains about this, but interestingly it only highlights the first overload signature (the one with Literal[True]
) saying that it does not match that of the supertype.
Upvotes: 2
Views: 775