auto_null_enum

The auto_null_member() class decorator is used to automatically add the null member to an Enum.

The Null Member

The null member is intended to be a sentinel value for the Enum. On creation, the null member is created from the module level configuration, which can be changed with calls to set_auto_null(). The name and value used by the class are stored internally in the class itself, so calls to set_auto_null will not impact any classes already created. The default name and value are `Null` and None respectively:

from enum import Enum
from extendableenum import set_auto_null, auto_null_member

@auto_null_member
class Defualt(Enum):
    pass

set_auto_null('CUSTOM', 'Null')

@auto_null_member
class Custom(Enum):
    pass

Default.__members__
Custom.__members__
>>> {'NULL': <Defualt.NULL: None>}
>>> {'CUSTOM: <Custom.CUSTOM: 'Null'>}

Decorating Classes with auto_null_member

The auto_null_member decorator can only be applied to classes with the EnumMeta metaclass. Applying the decorator to any other class will raise a TypeError.

If the decorated class does not define any members, it is considered a mixin class and the inheritable_enum() decorator is automatically applied:

Default.__inheritable_members__
>>> ['NULL']

Otherwise, it is simply considered a normal Enum with the null member. If automatically added, the null member will always be inserted as the first member:

set_auto_null('NULL', None)

@auto_null_member
class Directions(Enum):
    NORTH = 0
    SOUTH = 1
    DENNIS = 2

Directions.__members__
>>> {'NULL': <Directions.NULL: None>, 'NORTH': <Directions.NORTH: 0>, 'SOUTH': <Directions.SOUTH: 1>, 'DENNIS': <Directions.DENNIS: 2>}

If you want to be verbose (and possibly to silence annoying IDE warnings), you may manually define the null member as long as the value assigned matches the module configuration. This can also be used to change the ordering of the null member:

@auto_null_member   # Decorator has no effect in this case
class SameDirections(Enum):
    NORTH = 0
    SOUTH = 1
    NULL = None
    DENNIS = 2

SameDirections.__members__
>>> {'NORTH': <SameDirections.NORTH: 0>, 'SOUTH': <SameDirections.SOUTH: 1>, 'NULL': <SameDirections.NULL: None>, 'DENNIS': <SameDirections.DENNIS: 2>}

You can also create an alias for the null member using the configured value:

@auto_null_member
class NullAlias(Enum):
    NULL_ALIAS = None

NullAlias.NULL_ALIAS is NullAlias.NULL
>>> True

You cannot, however, redefine the null member with a new value, as this will raise a ValueError:

try:
    @auto_null_member
    class RedefineNull(Enum):
        A = 1
        NULL = 2
except ValueError:
    print('Cannot redefine the null member')
>>> Cannot redefine the null member

OrderedEnums and the Null Member

If you have an OrderedEnum:

@auto_null_member
class NullGrade(OrderedEnum):
    A = 5
    B = 4
    C = 3
    D = 2
    F = 1

the auto_null_member decorator will automatically adjust any of the comparison functions (ie: __le__, __lt__, __ge__ and __gt__) defined in the class to consider the null member. In cases where neither value in the comparison are the null member, or if they are of different classes, comparison is deferred to the originally defined functions . Otherwise, the null member will always compare as less than a valid member.

Note

If the first value in the comparison is the null member, the second value is treated as a valid member, even if it is also the null member:

NullGrade.NULL < NullGrade.A
NullGrade.NULL <= NullGrade.B
NullGrade.NULL > NullGrade.C
NullGrade.NULL >= NullGrade.C
NullGrade.NULL < NullGrade.NULL
NullGrade.NULL <= NullGrade.NULL
NullGrade.NULL > NullGrade.NULL
NullGrade.NULL >= NullGrade.NULL
>>> True
>>> True
>>> False
>>> False
>>> True
>>> True
>>> False
>>> False

AutoNullEnum

AutoNullEnum is a base mixin class for null member Enum s. A custom base class can easily be created, as seen in this example. Since AutoNullEnum does not define any members other than the null member, it is inheritable:

class AutoNullDerived(AutoNullEnum):
    A = 1
    B = 2

AutoNullDerived.auto_null_member()
bool(AutoNullDerived.A)
bool(AutoNullDerived.auto_null_member())
>>> AutoNullEnum.NULL
>>> True
>>> False

Decorated and Undecorated Subclasses

When subclassing an auto_null_member decorated class, the subclass may or may be decorated as well. If decorated, the subclass will have access to both the base class null member as well as it’s own distinct null member:

@auto_null_member
class Decorated(AutoNullEnum):
    A = 1
    B = 2

class Undecorated(AutoNullEnum):
    A = 1
    B = 2

Decorated.auto_null_member()
Undecorated.auto_null_member()
super(Decorated, Decorated).NULL
>>> Decorated.NULL
>>> AutoNullEnum.NULL
>>> AutoNullEnum.NULL