pythonclassoopenumsoverriding

How to check if string exists in Enum of strings?


I have created the following Enum:

from enum import Enum

class Action(str, Enum):
    NEW_CUSTOMER = "new_customer"
    LOGIN = "login"
    BLOCK = "block"

I have inherited from str, too, so that I can do things such as:

action = "new_customer"
...
if action == Action.NEW_CUSTOMER:
    ...

I would now like to be able to check if a string is in this Enum, such as:

if "new_customer" in Action:
    ....

I have tried adding the following method to the class:

def __contains__(self, item):
    return item in [i for i in self]

However, when I run this code:

print("new_customer" in [i for i in Action])
print("new_customer" in Action)

I get this exception:

True
Traceback (most recent call last):
  File "/Users/kevinobrien/Documents/Projects/crazywall/utils.py", line 24, in <module>
    print("new_customer" in Action)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/enum.py", line 310, in __contains__
    raise TypeError(
TypeError: unsupported operand type(s) for 'in': 'str' and 'EnumMeta'

Solution

  • I just bumped into this problem today (2020-12-09); I had to change a number of subpackages for Python 3.8.

    Perhaps an alternative to the other solutions here is the following, inspired by the excellent answer here to a similar question, as well as @MadPhysicist's answer on this page:

    from enum import Enum, EnumMeta
    
    
    class MetaEnum(EnumMeta):
        def __contains__(cls, item):
            try:
                cls(item)
            except ValueError:
                return False
            return True    
    
    
    class BaseEnum(Enum, metaclass=MetaEnum):
        pass
    
    
    class Stuff(BaseEnum):
        foo = 1
        bar = 5
    

    Tests (python >= 3.7; tested up to 3.10):

    >>> 1 in Stuff
    True
    
    >>> Stuff.foo in Stuff
    True
    
    >>> 2 in Stuff
    False
    
    >>> 2.3 in Stuff
    False
    
    >>> 'zero' in Stuff
    False