cardinal_pythonlib.enumlike


Original code copyright (C) 2009-2022 Rudolf Cardinal (rudolf@pobox.com).

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

See https://docs.python.org/3/library/enum.html.

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

LowerCaseAutoStringObject:

  • IDEs don’t understand their values, so get types wrong
from enum import Enum

class Colour(Enum):
    red = 1
    green = 2
    blue = 3

Colour.red  # <Colour.red: 1>
Colour.red.name  # 'red'
Colour.red.value  # 1
Colour['red']  # <Colour.red: 1>

Colour.red = 4  # AttributeError: Cannot reassign members.

Then, for fancier things below, note that:

metaclass
    __prepare__(mcs, name, bases)
        ... prepares (creates) the class namespace
        ... use if you don't want the namespace to be a plain dict()
        ... https://docs.python.org/3/reference/datamodel.html
        ... returns the (empty) namespace
    __new__(mcs, name, bases, namespace)
        ... called with the populated namespace
        ... makes and returns the class object, cls

class
    __new__(cls)
        ... controls the creation of a new instance; static classmethod
        ... makes self

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

Dictionary with attribute access; see https://stackoverflow.com/questions/4984647

class cardinal_pythonlib.enumlike.AutoNumberEnum[source]

As per https://docs.python.org/3/library/enum.html (in which, called AutoNumber).

Usage:

class Color(AutoNumberEnum):
    red = ()
    green = ()
    blue = ()

Color.green.value == 2  # True
class cardinal_pythonlib.enumlike.AutoNumberObject

From comment by Duncan Booth at https://www.acooke.org/cute/Pythonssad0.html, with trivial rename.

Usage:

class MyThing(AutoNumberObject):
    a
    b

MyThing.a
# 1
MyThing.b
# 2
class cardinal_pythonlib.enumlike.AutoStrEnum[source]

Base class for name=value str enums.

Example:

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

print(Animal.horse)
print(Animal.horse == 'horse')
print(Animal.horse.name, Animal.horse.value)

See https://stackoverflow.com/questions/32214614/automatically-setting-an-enum-members-value-to-its-name/32215467 and then inherit from StrEnum rather than Enum.

class cardinal_pythonlib.enumlike.AutoStrEnumMeta[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

Usage:

class Fish(AutoStringObject):
    Thing
    Blah

Fish.Thing  # 'Thing'
class cardinal_pythonlib.enumlike.CaseInsensitiveEnumMeta[source]

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

https://stackoverflow.com/questions/42658609/how-to-construct-a-case-insensitive-enum

Example:

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[source]

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

Example:

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

print(AnimalLC.Horse)
print(AnimalLC.Horse == 'horse')
print(AnimalLC.Horse.name, AnimalLC.Horse.value)
class cardinal_pythonlib.enumlike.LowerCaseAutoStrEnumMeta[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

Usage:

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 https://stackoverflow.com/questions/455059, modified for __init__.

class cardinal_pythonlib.enumlike.StrEnum[source]

StrEnum:

  • 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.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.