Source code for enumagic._mapping

"""Mapping enum module."""

# Copyright (c) 2020-2024 ObserverOfTime
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
#   claim that you wrote the original software. If you use this software
#   in a product, an acknowledgment in the product documentation would be
#   appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
#   misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.

from enum import Enum, EnumMeta
from typing import Any, Iterator, TypeVar

_ET = TypeVar('_ET', bound=type[Enum])


[docs] class MappingMeta(EnumMeta): """Mapping enum metaclass."""
[docs] def __iter__(cls) -> Iterator[tuple[int, str]]: """ Iterate over the values of the enum. Yields: :obj:`tuple` of :obj:`int`, :obj:`str` : The next tuple where the first element is the ``index`` of the enum instance and the second element is the ``label`` of the enum instance. Examples: >>> list(MappingExample) [(0, 'Alice'), (1, 'Bob')] """ return (e.value for e in super().__iter__())
[docs] def __call__(cls, value: Any) -> _ET: """ Get an enum instance from the given value. Args: value (:obj:`~typing.Any`): The value to look for in the members of the enum. Returns: :obj:`~enum.Enum`: An enum instance that corresponds to the value. Raises: :obj:`ValueError`: If the given value is invalid. Examples: >>> MappingExample(0) <MappingExample.A: (0, 'Alice')> >>> MappingExample('Bob') <MappingExample.B: (1, 'Bob')> """ if isinstance(value, int): value = next((v for v in cls if v[0] == value), value) elif isinstance(value, str): value = next((v for v in cls if v[1] == value), value) return super().__call__(value)
@property def items(cls) -> dict[str, int]: """ Get a mapping of ``label``/``index`` pairs. Type :obj:`dict` of :obj:`str` to :obj:`int` Examples: >>> MappingExample.items {'Alice': 0, 'Bob': 1} """ return {lbl: idx for idx, lbl in cls} @property def indices(cls) -> tuple[int, ...]: """ Get the indices of the enum. Type :obj:`tuple` of :obj:`int` Examples: >>> MappingExample.indices (0, 1) """ return tuple(val[0] for val in cls) @property def labels(cls) -> tuple[str, ...]: """ Get the labels of the enum. Type :obj:`tuple` of :obj:`str` Examples: >>> MappingExample.labels ('Alice', 'Bob') """ return tuple(val[1] for val in cls)
[docs] class MappingEnum(Enum, metaclass=MappingMeta): """ Enum class which maps labels to indices. Attributes: index (int): An integer that will be used as the index. label (str): A string that will be used as the label. Examples: >>> class MappingExample(MappingEnum): ... A = 0, 'Alice' ... B = 1, 'Bob' >>> '%d, %s' % (MappingExample.B.index, Example.B.label) '1, Bob' .. autoattribute:: __class__ :annotation: alias of :class:`enumagic.MappingMeta` """ def __init__(self, index: int, label: str): if index in self.__class__.indices: raise ValueError(f'Duplicate index found: {index}') if label in self.__class__.labels: raise ValueError(f'Duplicate label found: {label}') self.index, self.label = index, label def __str__(self) -> str: """ Return the instance as a string. Returns: :obj:`str`: The label of the instance. Examples: >>> str(MappingExample.A) 'Alice' """ return self.label
[docs] def __int__(self) -> int: """ Return the instance as an integer. Returns: :obj:`int`: The index of the instance. Examples: >>> int(MappingExample.A) 0 """ return self.index
[docs] def __index__(self) -> int: """ Return the instance as an index. Returns: :obj:`int`: The index of the instance. Examples: >>> test = ['first', 'second'] >>> test[MappingExample.B] 'second' """ return self.index