Hi,
Somewhat related discussion on mypy: Confusing error message for a missing classmethod decorator · Issue #11791 · python/mypy · GitHub
An Enum
’s class method _missing_()
(docs) is typed in Typeshed as follows (code):
@classmethod
def _missing_(cls, value: object) -> Any: ...
That means that sub-classes like StrEnum
and IntEnum
also inherit that same signature. However, I expected those signatures to be adjusted for the sub-class, for example (code)
class StrEnum(str, ReprEnum):
def __new__(cls, value: str) -> Self: ...
_value_: str
@_magic_enum_attr
def value(self) -> str: ...
@staticmethod
def _generate_next_value_(name: str, start: int, count: int, last_values: list[str]) -> str: ...
seems to miss
def _missing_(cls: value: str) -> Self # or return `str`
I’m also a little unclear on the return type here. The docs say
By default it does nothing, but can be overridden to implement custom search behavior
which I assume means that the method searches for and returns instances of _value_
or itself. See also discussion Enum classes and Self.
All this head-scratching because I’m trying to type such a custom _missing_()
method of a StrEnum
sub-class and I get conflicting errors. When typing value: str
then
error: Argument 1 of "_missing_" is incompatible with supertype "enum.Enum"; supertype defines the argument type as "object" [override]
def _missing_(cls, value: str) -> typing.Self:
^~~~~~~~~~
note: This violates the Liskov substitution principle
note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
or when typing value: object
then
error: Argument 1 to "MyStrEnum" has incompatible type "object"; expected "str" [arg-type]
obj = cls(value)
^~~~~
error: Incompatible types in assignment (expression has type "object", variable has type "str") [assignment]
obj._value_ = value
^~~~~
So I changed the code in our sub-class to
@typing.overload
@classmethod
def _missing_(cls, value: str) -> typing.Self: ...
@typing.overload
@classmethod
def _missing_(cls, value: object) -> typing.Self: ...
@classmethod
def _missing_(cls, value):
# Implementation goes here.
And this now complains about
error: Function is missing a type annotation [no-untyped-def]
def _missing_(cls, value):
^
Hm, any recommendations?