Source code for openfisca_core.indexed_enums.enum

from __future__ import annotations

import enum
from typing import Union

import numpy

from . import ENUM_ARRAY_DTYPE, EnumArray


[docs]class Enum(enum.Enum): """ Enum based on `enum34 <https://pypi.python.org/pypi/enum34/>`_, whose items have an index. """ # Tweak enums to add an index attribute to each enum item def __init__(self, name: str) -> None: # When the enum item is initialized, self._member_names_ contains the # names of the previously initialized items, so its length is the index # of this item. self.index = len(self._member_names_) # Bypass the slow Enum.__eq__ __eq__ = object.__eq__ # In Python 3, __hash__ must be defined if __eq__ is defined to stay # hashable. __hash__ = object.__hash__
[docs] @classmethod def encode( cls, array: Union[ EnumArray, numpy.int_, numpy.float_, numpy.object_, ], ) -> EnumArray: """ Encode a string numpy array, an enum item numpy array, or an int numpy array into an :any:`EnumArray`. See :any:`EnumArray.decode` for decoding. :param numpy.ndarray array: Array of string identifiers, or of enum items, to encode. :returns: An :any:`EnumArray` encoding the input array values. :rtype: :any:`EnumArray` For instance: >>> string_identifier_array = asarray(['free_lodger', 'owner']) >>> encoded_array = HousingOccupancyStatus.encode(string_identifier_array) >>> encoded_array[0] 2 # Encoded value >>> free_lodger = HousingOccupancyStatus.free_lodger >>> owner = HousingOccupancyStatus.owner >>> enum_item_array = asarray([free_lodger, owner]) >>> encoded_array = HousingOccupancyStatus.encode(enum_item_array) >>> encoded_array[0] 2 # Encoded value """ if isinstance(array, EnumArray): return array # String array if isinstance(array, numpy.ndarray) and \ array.dtype.kind in {'U', 'S'}: array = numpy.select( [array == item.name for item in cls], [item.index for item in cls], ).astype(ENUM_ARRAY_DTYPE) # Enum items arrays elif isinstance(array, numpy.ndarray) and \ array.dtype.kind == 'O': # Ensure we are comparing the comparable. The problem this fixes: # On entering this method "cls" will generally come from # variable.possible_values, while the array values may come from # directly importing a module containing an Enum class. However, # variables (and hence their possible_values) are loaded by a call # to load_module, which gives them a different identity from the # ones imported in the usual way. # # So, instead of relying on the "cls" passed in, we use only its # name to check that the values in the array, if non-empty, are of # the right type. if len(array) > 0 and cls.__name__ is array[0].__class__.__name__: cls = array[0].__class__ array = numpy.select( [array == item for item in cls], [item.index for item in cls], ).astype(ENUM_ARRAY_DTYPE) return EnumArray(array, cls)