I've written an enum.Enum type with a couple of members. Now I want to write a "selector" @classmethod that will return one of the members of the Enum based on arguments, and I don't know how to type hint it properly.
Here's what I have to far:
from enum import Enum, auto
from typing import TypeVar, Type
_StringSizeT = TypeVar("_StringSizeT", bound="StringSize")
class StringSize(Enum):
SMALL = auto()
BIG = auto()
@classmethod
def from_string(cls: Type[_StringSizeT], source_string: str) -> _StringSizeT:
n_chars = len(source_string)
if n_chars <= 10:
return cls.SMALL
return cls.BIG
The above use of TypeVar(), etc is me trying to follow approach of Martijn Pieters' post in "Can you annotate return type when value is instance of cls?" for @classmethod factories, but applying them to Enum @classmethods that return one of the enum members.
Unfortunately, mypy does not like the types of my return statements:
error: Incompatible return value type (got "StringSize", expected "_StringSizeT")
This is because the properties of this @classmethod are different than in that post: I'm not returning an instance of the class, but a class attribute, or in enum-speak, a member.
How can I fix my method annotation here?
UPDATE: Ok, while writing this, I riffed on the advice of mypy and found that
-> "StringSize"
is acceptable. This is a little confusing because, again, I'm not returning an instance, but I'll chalk that up to the metaprogramming machinery underneath Enum. Followup: Is there a non-string-literal type annotation I could use here instead? Through my experience, I've learned (maybe incorrectly) to dislike the string literal annotations. (Am I sacrificing anything with them?)
As discussed in the comment section, the correct annotation is the enum class itself:
from __future__ import annotations
class StringSize(Enum):
# ...
@classmethod
def from_string(cls, source_string: str) -> StringSize:
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With