# Stem Docs

## stem.util.enum

# Source code for stem.util.enum

    # Copyright 2011-2019, Damian Johnson and The Tor Project
    # See LICENSE for licensing information

    """
    Basic enumeration, providing ordered types for collections. These can be
    constructed as simple type listings...

    ::

      >>> from stem.util import enum
      >>> insects = enum.Enum('ANT', 'WASP', 'LADYBUG', 'FIREFLY')
      >>> insects.ANT
      'Ant'
      >>> tuple(insects)
      ('Ant', 'Wasp', 'Ladybug', 'Firefly')

    ... or with overwritten string counterparts...

    ::

      >>> from stem.util import enum
      >>> pets = enum.Enum(('DOG', 'Skippy'), 'CAT', ('FISH', 'Nemo'))
      >>> pets.DOG
      'Skippy'
      >>> pets.CAT
      'Cat'

    **Module Overview:**

    ::

      UppercaseEnum - Provides an enum instance with capitalized values

      Enum - Provides a basic, ordered  enumeration
        |- keys - string representation of our enum keys
        |- index_of - index of an enum value
        |- next - provides the enum after a given enum value
        |- previous - provides the enum before a given value
        |- __getitem__ - provides the value for an enum key
        +- __iter__ - iterator over our enum keys
    """

    import stem.util

    def UppercaseEnum(*args):
      """
      Provides an :class:`~stem.util.enum.Enum` instance where the values are
      identical to the keys. Since the keys are uppercase by convention this means
      the values are too. For instance...

      ::

        >>> from stem.util import enum
        >>> runlevels = enum.UppercaseEnum('DEBUG', 'INFO', 'NOTICE', 'WARN', 'ERROR')
        >>> runlevels.DEBUG
        'DEBUG'

      :param list args: enum keys to initialize with

      :returns: :class:`~stem.util.enum.Enum` instance with the given keys
      """

      return Enum(*[(v, v) for v in args])

    class Enum(object):
      """
      Basic enumeration.
      """

      def __init__(self, *args):
        from stem.util.str_tools import _to_camel_case

        # ordered listings of our keys and values
        keys, values = [], []

        for entry in args:
          if stem.util._is_str(entry):
            key, val = entry, _to_camel_case(entry)
          elif isinstance(entry, tuple) and len(entry) == 2:
            key, val = entry
          else:
            raise ValueError('Unrecognized input: %s' % args)

          keys.append(key)
          values.append(val)
          setattr(self, key, val)

        self._keys = tuple(keys)
        self._values = tuple(values)

      def keys(self):
        """
        Provides an ordered listing of the enumeration keys in this set.

        :returns: **list** with our enum keys
        """

        return list(self._keys)

      def index_of(self, value):
        """
        Provides the index of the given value in the collection.

        :param str value: entry to be looked up

        :returns: **int** index of the given entry

        :raises: **ValueError** if no such element exists
        """

        return self._values.index(value)

      def next(self, value):
        """
        Provides the next enumeration after the given value.

        :param str value: enumeration for which to get the next entry

        :returns: enum value following the given entry

        :raises: **ValueError** if no such element exists
        """

        if value not in self._values:
          raise ValueError('No such enumeration exists: %s (options: %s)' % (value, ', '.join(self._values)))

        next_index = (self._values.index(value) + 1) % len(self._values)
        return self._values[next_index]

      def previous(self, value):
        """
        Provides the previous enumeration before the given value.

        :param str value: enumeration for which to get the previous entry

        :returns: enum value proceeding the given entry

        :raises: **ValueError** if no such element exists
        """

        if value not in self._values:
          raise ValueError('No such enumeration exists: %s (options: %s)' % (value, ', '.join(self._values)))

        prev_index = (self._values.index(value) - 1) % len(self._values)
        return self._values[prev_index]

      def __getitem__(self, item):
        """
        Provides the values for the given key.

        :param str item: key to be looked up

        :returns: **str** with the value for the given key

        :raises: **ValueError** if the key doesn't exist
        """

        if item in vars(self):
          return getattr(self, item)
        else:
          keys = ', '.join(self.keys())
          raise ValueError("'%s' isn't among our enumeration keys, which includes: %s" % (item, keys))

      def __iter__(self):
        """
        Provides an ordered listing of the enums in this set.
        """

        for entry in self._values:
          yield entry