Skip to main content

Lib/enum.py (part 2)

Source:

cpython 3.14 @ ab2d84fe1023/Lib/enum.py

This annotation covers Flag, IntFlag, and 3.11+ additions. See lib_enum_detail for Enum, EnumMeta.__new__, member lookup, and IntEnum.

Map

LinesSymbolRole
1-100FlagBitwise-composable enum; &, `
101-250_decomposeSplit a composite flag into canonical members
251-400IntFlagFlag + int mixin — arbitrary ints are valid
401-550_missing_Hook called when lookup fails; default raises ValueError
551-700auto()Automatic value generation; default _generate_next_value_
701-850StrEnumstr + Enum; values are lowercase names by default
851-1000member / nonmemberMark a descriptor as an enum member or exclude it
1001-1200verify()Post-definition checks: UNIQUE, CONTINUOUS, NAMED_FLAGS

Reading

Flag bitwise operations

# CPython: Lib/enum.py:880 Flag.__or__
class Flag(Enum):
def __or__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.__class__(self._value_ | other._value_)

def __and__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.__class__(self._value_ & other._value_)

def __xor__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.__class__(self._value_ ^ other._value_)

def __invert__(self):
# Invert within the set of defined bits
result = self.__class__(self._flag_mask_ ^ self._value_)
return result

_decompose

# CPython: Lib/enum.py:980 _decompose
def _decompose(flag, value):
"""Return list of canonical Flag members for a composite value."""
not_covered = value
negative = value < 0
members = []
for member in flag:
member_value = member._value_
if member_value and member_value & value == member_value:
members.append(member)
not_covered &= ~member_value
if not negative and not_covered:
# Pseudo-member for leftover bits
members.append(flag._create_pseudo_member_(not_covered))
members.sort(key=lambda m: m._value_, reverse=True)
return members, not_covered

repr(Permission.READ | Permission.WRITE) uses _decompose to list the constituent members.

_missing_

# CPython: Lib/enum.py:540 EnumType.__call__ (uses _missing_)
# When MyEnum(value) fails lookup, _missing_ is called:
@classmethod
def _missing_(cls, value):
# Default: raise ValueError
raise ValueError(f'{value!r} is not a valid {cls.__name__}')

# Override for auto-creation:
class Color(Enum):
@classmethod
def _missing_(cls, value):
obj = object.__new__(cls)
obj._value_ = value
obj._name_ = str(value)
return obj

auto()

# CPython: Lib/enum.py:620 auto
class auto(int):
"""Placeholder: value assigned by _generate_next_value_."""
_value_ = 0
@staticmethod
def _generate_next_value_(name, start, count, last_values):
"""Default: increment from 1."""
for last_value in reversed(last_values):
try:
return last_value + 1
except TypeError:
pass
return start

verify(UNIQUE)

# CPython: Lib/enum.py:1100 verify
def verify(*checks):
"""Decorator that validates the enum after definition."""
def decorator(enumeration):
for check in checks:
if check is UNIQUE:
# Ensure no two names map to the same value
aliases = [n for n, v in enumeration.__members__.items()
if v.name != n]
if aliases:
raise ValueError(f'aliases found in {enumeration!r}: '
+ ', '.join(aliases))
return enumeration
return decorator

@verify(UNIQUE) raises ValueError if any aliases (duplicate values) are found.

gopy notes

enum is pure Python. Flag.__or__ calls self.__class__(value) which invokes EnumType.__call__, handled by gopy's type call dispatch in objects/type_call.go. auto() subclasses int, so gopy treats it as a Python int with an extra attribute.