Ordering enum value in python

Robert picture Robert · Aug 23, 2013 · Viewed 8.5k times · Source

I would like to be able to arrange the ordering of Enum. Has somebody suggestions how this can be solved?

The following Enum meta class is using:

class EnumMeta(type):
    def __new__(typ, name, bases, attrs):
        cls_attrs = {}
        cls_choices = []
        for attr_name, value in attrs.items():
            cls_attrs[attr_name] = attr_name.lower()
            if not attr_name.startswith("__"):
                cls_choices.append((attr_name.lower(), value))

        def choices(cls):
            return cls_choices

        def values(cls, value=None):
            if value is None:
                return {choice[0]: unicode(choice[1]) for choice in cls.choices()}
            elif isinstance(value, list):
                return {choice[0]: unicode(choice[1]) for choice in cls.choices() if choice[0] in value}
            else:
                return unicode(dict(cls.choices()).get(value))

        def keys(cls, nil=False):
            items = [item[0] for item in cls.choices()]
            if nil:
                items.append('')

            return items

        def combined_length(cls):
            return len(",".join(cls.values().keys()))

        def max_length(cls):
            return max(map(len, cls.values().keys()))

        cls_attrs['choices'] = classmethod(choices)
        cls_attrs['values'] = classmethod(values)
        cls_attrs['keys'] = classmethod(keys)
        cls_attrs['combined_length'] = classmethod(combined_length)
        cls_attrs['max_length'] = classmethod(max_length)

        return type(name, bases, cls_attrs)

An example of an Enum is as follow:

class SideHemType:
    __ordering__ = ['double', 'single']
    __metaclass__ = EnumMeta

    Single = "Single side hem for opaque fabrics"
    Double = "Double side hem for transparent fabrics"


  class TestEnumOrdering:
        print SideHemType.keys()
        print SideHemType.values() 

By printing the Enum SideHemType first Double is printed and then Single. But I would like first Single and then Double.

Answer

Ethan Furman picture Ethan Furman · Aug 23, 2013

If you are using Python3.4 you can use the new enum.Enum type, which remembers the order the enum members are declared in.

If you are using an earlier Python, you should use the enum34 package available from PyPI, which supports Pythons back to 2.4.

The enum34 package, if used in Python3, also remembers the order of member declarations. If used in Python 2 it supports an extra _order_ attribute:

from enum import Enum

class SideHemType(Enum):

    _order_ = 'Single Double'  # only needed in Python 2

    Single = "Single side hem for opaque fabrics"
    Double = "Double side hem for transparent fabrics"

    @classmethod
    def combined_length(cls):
        return len(",".join(mbr.name for mbr in cls))

    @classmethod
    def max_length(cls):
        return max(map(len, (mbr.name for mbr in cls)))


print list(SideHemType)  # [SideHemType.Single, SideHemType.Double]

print SideHemType.Double.value  # "Double side hem for transparent fabrics"