Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to construct a case insensitive enum?

I have a simple Python 2.7 enum:

from enum import Enum

class Label(enum):
    RedApple = 1
    GreenApple = 2

I would like to be able create enum objects using case-insensitive keys:

fruitname = "redapple"
a = Label[fruitname]

I've tried to create an __init__ method:

def __init__(self, key):
    super(Label, self).__init__()
    pass # do comparison here

but I keep running into errors:

super(Label, self).__init__()
NameError: global name 'Label' is not defined

I'd like to do a comparison on key.lower().strip(). Is this even possible?

like image 235
Hephaestus Avatar asked Mar 07 '17 21:03

Hephaestus


People also ask

Is enum case sensitive?

I'm also a fan of simple things – and believe it's simpler in implementation to say enum values are case-insensitive, that implementations will always naturally produce values in uppercase, than it is to special-case handling in all languages that the deserialized values are uppercase, and may fill an UNKNOWN value.

Can enum be lower case?

Java conventions are that enum names are all uppercase, which immediately causes problems if you want to serialize the enum in another form. But when you serialize those enum values, you want to use lowercase values of "left", "top", "right", and "bottom". No problem—you can override Side.

Does enum have to be all caps?

Because they are constants, the names of an enum type's fields are in uppercase letters. You should use enum types any time you need to represent a fixed set of constants.

Is Java enum valueOf case sensitive?

valueOf method is case-sensitive and invalid String will result in IllegalArgumentException. In short, The string passed to the valueOf method of Java enum must be the same as the String returned by name() method like TrafficSigal.RED.name() returns RED and you should pass RED to valueOf() to get TrafficSignal.


2 Answers

enum have missing function which can be overridden to make enum case insensitive. As per documentation https://docs.python.org/3.11/howto/enum.html missing – a lookup function used when a value is not found; may be overridden

example

class Status(enum.Enum):
   @classmethod
   def _missing_(cls, value):
      for member in cls:
         if member.value == value.upper():
            return member
   SUCCESS = 'SUCCESS'
   FAILURE = 'FAILURE'

print(Status('success'))

Output

Status.SUCCESS

like image 92
codingclues Avatar answered Oct 06 '22 18:10

codingclues


Not 100% sure this will work in Python 2.7, but I came up with a simple way to make it work exactly as requested for Python 3.6+.

The idea is that lookup for names is done by the class using square brackets, which means that it uses __getitem__ from the metaclass. So you can make a simple metaclass that implements a case insensitive search. Since it will extend the existing EnumMeta, it will be totally compatible with existing enums:

class CaseInsensitiveEnumMeta(EnumMeta):
    def __getitem__(self, item):
        if isinstance(item, str):
            item = item.upper()
        return super().__getitem__(item)

This presupposes that your enums are all uppercase. Using it is pretty straightforward:

class Label(Enum, metaclass=CaseInsensitiveEnumMeta):
    REDAPPLE = 1
    GREENAPPLE = 2

I'm not sure you even need Enum in this case. The catch here is that your enums have to be all uppercase for this to work. If you want to have a truly insensitive search, you would have to make sure that all of the keys in __members__ are properly casefolded.

In the meantime, you can do

>>> Label['GreenApple']
Label.GREENAPPLE
like image 23
Mad Physicist Avatar answered Oct 06 '22 17:10

Mad Physicist