Description
Consider the following snippet:
from abc import abstractmethod
from typing import Protocol
class HasX(Protocol):
@property
@abstractmethod
def x(self) -> int: ...
class Nominal(HasX):
@property
def x(self) -> int:
raise AttributeError
class Structural:
@property
def x(self) -> int:
raise AttributeError
def needs_obj_with_x(obj: HasX) -> None:
print(obj.x)
needs_obj_with_x(Nominal())
needs_obj_with_x(Structural())
This snippet will fail at runtime, as accessing the x
attribute on either an instance of Nominal
or an instance of Structural
will result in AttributeError
being raised. However, neither mypy nor pyright sees any issue with this code, which surprises me. I would have expected a type checker to complain about the Nominal.x
property and the Structural.x
property, since they are both annotated as returning int
yet neither of them will ever return an int
. I would have expected a type checker to demand that the x
property on both Nominal
and Structural
should either have at least one return statement (that returns an int
), or should be explicitly decorated with @abstractmethod
.
Is this a missing feature from mypy and pyright? Or is there a reason for this not to be implemented?
(I haven't checked the behaviour of other type checkers.)