Original code copyright (C) 2009-2022 Rudolf Cardinal (

This file is part of cardinal_pythonlib.

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Enum-based classes


The good things about enums are:

  • they are immutable

  • they are “class-like”, not “instance-like”

  • they can be accessed via attribute (like an object) or item (like a dict):

  • you can add a @unique decorator to ensure no two have the same value

  • IDEs know about them

AttrDict’s disadvantages are:

  • more typing / DRY

  • IDEs don’t know about them

Plain old objects:

  • not immutable

  • no dictionary access – though can use getattr()

  • but otherwise simpler than enums


  • IDEs don’t understand their values, so get types wrong

from enum import Enum

class Colour(Enum):
    red = 1
    green = 2
    blue = 3  # < 1>  # 'red'  # 1
Colour['red']  # < 1> = 4  # AttributeError: Cannot reassign members.

Then, for fancier things below, note that:

    __prepare__(mcs, name, bases)
        ... prepares (creates) the class namespace
        ... use if you don't want the namespace to be a plain dict()
        ... returns the (empty) namespace
    __new__(mcs, name, bases, namespace)
        ... called with the populated namespace
        ... makes and returns the class object, cls

        ... controls the creation of a new instance; static classmethod
        ... makes self

        ... controls the initialization of an instance
class cardinal_pythonlib.enumlike.AttrDict(*args, **kwargs)[source]

Dictionary with attribute access; see

class cardinal_pythonlib.enumlike.AutoNumberEnum(value)[source]

As per (in which, called AutoNumber).


class Color(AutoNumberEnum):
    red = ()
    green = ()
    blue = () == 2  # True
class cardinal_pythonlib.enumlike.AutoNumberObject

From comment by Duncan Booth at, with trivial rename.


class MyThing(AutoNumberObject):

# 1
# 2
class cardinal_pythonlib.enumlike.AutoStrEnum(value)[source]

Base class for name=value str enums.


class Animal(AutoStrEnum):
    horse = ()
    dog = ()
    whale = ()

print( == 'horse')

See and then inherit from StrEnum rather than Enum.

class cardinal_pythonlib.enumlike.AutoStrEnumMeta(cls, bases, oldclassdict)[source]

Scan through oldclassdict and convert any value that is a plain tuple into a str of the name instead.

class cardinal_pythonlib.enumlike.AutoStringObject


class Fish(AutoStringObject):

Fish.Thing  # 'Thing'
class cardinal_pythonlib.enumlike.CaseInsensitiveEnumMeta(cls, bases, classdict)[source]

An Enum that permits lookup by a lower-case version of its keys.


from enum import Enum
from cardinal_pythonlib.enumlike import CaseInsensitiveEnumMeta

class TestEnum(Enum, metaclass=CaseInsensitiveEnumMeta):
    REDAPPLE = 1
    greenapple = 2
    PineApple = 3

TestEnum["REDAPPLE"]  # <TestEnum.REDAPPLE: 1>
TestEnum["redapple"]  # <TestEnum.REDAPPLE: 1>
TestEnum["greenapple"]  # <TestEnum.greenapple: 2>
TestEnum["greenappLE"]  # <TestEnum.greenapple: 2>
TestEnum["PineApple"]  # <TestEnum.PineApple: 3>
TestEnum["PineApplE"]  # <TestEnum.PineApple: 3>
class cardinal_pythonlib.enumlike.EnumDict[source]

A copy of enum._EnumDict from Python 3.6 that we are allowed to access and doesn’t vanish in Python 3.9.

Track enum member order and ensure member names are not reused.

EnumMeta will use the names found in self._member_names as the enumeration member names.

class cardinal_pythonlib.enumlike.LowerCaseAutoStrEnum(value)[source]

Base class for name=value str enums, forcing lower-case values.


class AnimalLC(LowerCaseAutoStrEnum):
    Horse = ()
    Dog = ()
    Whale = ()

print(AnimalLC.Horse == 'horse')
print(, AnimalLC.Horse.value)
class cardinal_pythonlib.enumlike.LowerCaseAutoStrEnumMeta(cls, bases, oldclassdict)[source]

Scan through oldclassdict and convert any value that is a plain tuple into a str of the name instead.

class cardinal_pythonlib.enumlike.LowerCaseAutoStringObject


class Wacky(LowerCaseAutoStringObject):
    Thing  # or can use Thing = () to avoid IDE complaints
    OtherThing = ()

Wacky.Thing  # 'thing'
Wacky.OtherThing  # 'otherthing'
class cardinal_pythonlib.enumlike.OrderedNamespace(*args)[source]

As per, modified for __init__.

class cardinal_pythonlib.enumlike.StrEnum(value)[source]


  • makes str(myenum.x) give str(myenum.x.value)

  • adds a lookup function (from a string literal)

  • adds ordering by value

cardinal_pythonlib.enumlike.keys_descriptions_from_enum(enum: Type[Enum], sort_keys: bool = False, keys_to_lower: bool = False, keys_to_upper: bool = False, key_to_description: str = ': ', joiner: str = ' // ') Tuple[List[str], str][source]

From an Enum subclass, return (keys, descriptions_as_formatted_string). This is a convenience function used to provide command-line help for options involving a choice of enums from an Enum class.