"""
Module with common and reused implementation of enums.
`Enumerated types (enums) <https://en.wikipedia.org/wiki/Enumerated_type#Python>`_ are data types that consists of
named values. This module provides extension to `aenum <https://pypi.org/project/aenum/>`_ package.
"""
__all__ = ["ExtendableEnum", "ValidatedEnum", "ByteEnum", "NibbleEnum",
"Endianness"]
from typing import Any
from aenum import Enum as AEnum
from aenum import IntEnum as AIntEnum
from aenum import StrEnum as AStrEnum
from aenum import extend_enum
from .common_types import validate_nibble, validate_raw_byte
[docs]
class ExtendableEnum(AEnum): # type: ignore
"""Enum that supports new members adding."""
[docs]
@classmethod
def add_member(cls, name: str, value: Any) -> "ExtendableEnum":
"""
Register a new member.
:param name: Name of a new member.
:param value: Value of a new member.
:raise ValueError: Such name or value is already in use.
:return: The new member that was just created.
"""
for member in cls:
if member.name == name:
raise ValueError(f"Name {name!r} is already in use.")
if member.value == value:
raise ValueError(f"Value '{value}' is already in use.")
extend_enum(cls, name, value)
return cls[name] # type: ignore
[docs]
class ValidatedEnum(AEnum): # type: ignore
"""Enum that supports members validation."""
[docs]
@classmethod
def is_member(cls, value: Any) -> bool:
"""
Check whether given argument is a member or a value stored by this Enum.
:param value: Value to check.
:return: True if given argument is a member or a value of this Enum, else False.
"""
try:
cls.validate_member(value)
except ValueError:
return False
return True
[docs]
@classmethod
def validate_member(cls, value: Any) -> "ValidatedEnum":
"""
Validate whether given argument is a member or a value stored by this Enum.
:param value: Value to validate.
:raise ValueError: Provided value is not a member neither a value of this Enum.
"""
try:
return cls(value)
except ValueError:
# pylint: disable=raise-missing-from
raise ValueError(f"Provided value is not a member of this Enum. Actual value: {value}")
[docs]
class ByteEnum(AIntEnum): # type: ignore
"""Enum which members are one byte integers (0x00-0xFF) only."""
def __new__(cls, value: int) -> "ByteEnum":
"""
Creation of a new member.
:param value: One byte integer.
"""
validate_raw_byte(value)
member = int.__new__(cls, value)
member._value_ = value # noqa: vulture
return member
[docs]
class NibbleEnum(AIntEnum): # type: ignore
"""Enum which members are one nibble (4 bits) integers (0x0-0xF) only."""
def __new__(cls, value: int) -> "NibbleEnum":
"""
Creation of a new member.
:param value: One nibble (4 bits) integer.
"""
validate_nibble(value)
member = int.__new__(cls, value)
member._value_ = value # noqa: vulture
return member
[docs]
class Endianness(ValidatedEnum, AStrEnum): # type: ignore
"""
Endianness values definitions.
`Endianness <https://en.wikipedia.org/wiki/Endianness>`_ determines order of bytes in a bytes sequence.
"""
LITTLE_ENDIAN: "Endianness" = "little" # type: ignore # noqa: vulture
"""Little Endian stores the most significant byte at the largest memory address and the least significant byte
at the smallest."""
BIG_ENDIAN: "Endianness" = "big" # type: ignore
"""Big Endian stores the most significant byte at the smallest memory address and the least significant byte
at the largest."""