Type hinting the Color class should work:
def get_color_return_something(some_color: Color):
print(some_color.value)
Answer from ibarrond on Stack OverflowType hinting the Color class should work:
def get_color_return_something(some_color: Color):
print(some_color.value)
You can try to use an option with type hint Literal.
From official PEP8 documentation we know that:
Literal it's type that can be used to indicate to type checkers that the corresponding variable or function parameter has a value equivalent to the provided literal (or one of several literals)
So in case if you need to use some specific values for a function argument it will be one of the best options. But this approach will not work fully as we expected, because of the type of the Enum values. Each value will have a type of Enum class. This means that for the code example below we will be able to put Color.GREEN as the function argument. So such a solution will be just information for developers, but not a mandatory rule for a function argument.
class Color(enum.Enum):
RED = '1'
BLUE = '2'
GREEN = '3'
print(type(Color.RED) # will return <enum 'Color'>
Code example:
from enum import Enum
from typing import Literal
class Color(Enum):
RED = '1'
BLUE = '2'
GREEN = '3'
def some_function(some_color: Literal[Color.RED, Color.BLUE]) -> None:
pass
The second option it's fully correct solution provided by @ibarrond from the post above with just a class type hint.
some_color: Color
So here you can choose the option to work with depending on your needs.
From my point of view we can try to specify possible Enum values for developers, to be more clear in our requirements for a function.
Generic versions of enum.Enum?
How to replicate the enum type hint?
Draft of typing spec chapter for enums - Typing - Discussions on Python.org
Convert enum to Literal type alias in Python typing - Stack Overflow
Videos
I made a Custom enum Base class that fixes some issues I had with the normal enum, mainly the nesting of enums to represent more complex strucures. It also makes the code a lot more maintainable.
What I wanted to know is how I can replicate the Enum type hint so that instead of security_level: Security.BASIC | Security.AVERAGE | ... I can just do security_level: Security. Aswell as an easier way to check compliance like isinstance (of course you can just check the base class but I want to know if this can be solved with proper type hinting too).
Example:
from ..data import EANEnum as _EANEnum
class Security(_EANEnum): # Changed to indices for easy selection from iterables
"""Baseclass for different security levels"""
BASIC = 0, "An attacker can reverse whatever if they have enough info on you pretty easily"
AVERAGE = 1, "A lot better than basic"
STRONG = 2, "Practically impossible to reverse or crack"
SUPER_STRONG = 3, "Great security, but at the cost of comfort features like readability and efficiency"Implementation: https://pastebin.com/p2CVSNJP
I'm afraid there's no such way. The first thing that comes to mind is iterating over enum's values to build a Literal type won't work, because Literal cannot contain arbitrary expressions. So, you cannot specify it explicitly:
# THIS DOES NOT WORK
def is_enabled(state: State | Literal[State.ENABLED.value, State.DISABLED.value]) -> bool:
...
There's an open issue on GitHub with the related discussion. Basically, you could have hardcoded literals for every Enum, but in that case, you need to update it in accordance with Enum updates, and one day it will be messy. So, I would either stick with State | str annotation or just State and expect your function to accept only enums.
Also, take into account that you do not need to explicitly create an Enum object to test its value, you can just write "enabled" == State.ENABLED as I mentioned in the comments.
It's very annoying that you can't easily create a Literal type hint for all the members of an enum, but one potential workaround if you have control of the enum (and can programmatically determine what the member name should be from the value) is to reverse the direction
Instead of creating a Literal type hint from the enum members, you can create an enum from the values in a Literal type hint using the functional API for Enum and typing.get_args
Your example would look like:
from enum import Enum
from typing import Literal, get_args
# variable naming might not be great here,
# but I figure it's good enough for the short example
StateValues = Literal["enabled", "disabled"]
State = Enum(
"State",
((state.upper(), state) for state in get_args(StateValues))
module="...", # fill in module and qualname to help with pickling
qualname="...",
)
def is_enabled(state: State | StateValues) -> bool:
return state is State.ENABLED or state == State.ENABLED.value
Huge downside to this approach is that now static analysis tools will flag State.ENABLED as an unknown attribute (and you lose the ability to put individual enum members in type hints or do exhaustiveness checking on enum members)
The functional API won't let you do everything that the class API does, but if all you need are the members to be defined, then this should work
Overall, this approach probably isn't worth it
First that comes to mind is matplotlib. Why are parameters strings? E.g. fig.legend(loc='topleft').
Wouldn't it be much more elegant for enum LegendPlacement.TOPLEFT to exist?
What was their reasoning when they decided "it'll be strings"?
EDIT: So many great answers already! Much to learn from this...