cpython: aad7443e62be (original) (raw)

Mercurial > cpython

changeset 103609:aad7443e62be

issue23591: add auto() for auto-generating Enum member values [#23591]

Ethan Furman ethan@stoneleaf.us
date Sat, 10 Sep 2016 23:36:59 -0700
parents feb1ae9d5381
children d00f15af75ea
files Doc/library/enum.rst Lib/enum.py Lib/test/test_enum.py
diffstat 3 files changed, 195 insertions(+), 31 deletions(-)[+] [-] Doc/library/enum.rst 99 Lib/enum.py 50 Lib/test/test_enum.py 77

line wrap: on

line diff

--- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -25,7 +25,8 @@ Module Contents This module defines four enumeration classes that can be used to define unique sets of names and values: :class:Enum, :class:IntEnum, and -:class:IntFlags. It also defines one decorator, :func:unique. +:class:IntFlags. It also defines one decorator, :func:unique, and one +helper, :class:auto. .. class:: Enum @@ -52,7 +53,11 @@ sets of names and values: :class:Enum, Enum class decorator that ensures only one name is bound to any one value. -.. versionadded:: 3.6 Flag, IntFlag +.. class:: auto +

+ +.. versionadded:: 3.6 Flag, IntFlag, auto Creating an Enum @@ -70,6 +75,13 @@ follows:: ... blue = 3 ... +.. note:: Enum member values +

+ .. note:: Nomenclature

+ +The values are chosen by :func:_generate_next_value_, which can be +overridden:: +

+ +.. note:: +

+ Iteration --------- @@ -597,7 +645,9 @@ Flag The last variation is :class:Flag. Like :class:IntFlag, :class:Flag members can be combined using the bitwise operators (&, |, ^, ~). Unlike :class:IntFlag, they cannot be combined with, nor compared against, any -other :class:Flag enumeration, nor :class:int. +other :class:Flag enumeration, nor :class:int. While it is possible to +specify the values directly it is recommended to use :class:auto as the +value and let :class:Flag select an appropriate value. .. versionadded:: 3.6 @@ -606,9 +656,9 @@ flags being set, the boolean evaluation >>> from enum import Flag >>> class Color(Flag):

Giving a name to the "no flags set" condition does not change its boolean value:: >>> class Color(Flag): ... black = 0

+ + Using :class:object """"""""""""""""""""" @@ -930,8 +994,11 @@ Supported _sunder_ names overridden

--- a/Lib/enum.py +++ b/Lib/enum.py @@ -10,7 +10,11 @@ except ImportError: from collections import OrderedDict -all = ['EnumMeta', 'Enum', 'IntEnum', 'Flag', 'IntFlag', 'unique'] +all = [

def _is_descriptor(obj): @@ -36,7 +40,6 @@ def is_sunder(name): name[-2:-1] != '' and len(name) > 2) - def _make_class_unpicklable(cls): """Make the given class un-picklable.""" def _break_on_call_reduce(self, proto): @@ -44,6 +47,12 @@ def _make_class_unpicklable(cls): cls.reduce_ex = _break_on_call_reduce cls.module = '' +class auto:

+ class _EnumDict(dict): """Track enum member order and ensure member names are not reused. @@ -55,6 +64,7 @@ class _EnumDict(dict): def init(self): super().init() self._member_names = []

def setitem(self, key, value): """Changes anything not dundered or not a descriptor. @@ -71,6 +81,8 @@ class _EnumDict(dict): 'generate_next_value', 'missing', ): raise ValueError('names are reserved for future Enum use')

@@ -81,11 +93,13 @@ class _EnumDict(dict): if key in self: # enum overwriting a descriptor? raise TypeError('%r already defined as: %r' % (key, self[key]))

-

Dummy value for Enum as EnumMeta explicitly checks for it, but of course

until EnumMeta finishes running the first time the Enum class doesn't exist.

This is also why there are checks in EnumMeta like if Enum is not None

@@ -366,10 +380,11 @@ class EnumMeta(type): names = names.replace(',', ' ').split() if isinstance(names, (tuple, list)) and isinstance(names[0], str): original_names, names = names, []

# Here, names is either an iterable of (name, value) or a mapping. for item in names: @@ -514,11 +529,15 @@ class Enum(metaclass=EnumMeta): # still not found -- try missing hook return cls.missing(value)

+ @classmethod def missing(cls, value): raise ValueError("%r is not a valid %s" % (value, cls.name)) @@ -616,8 +635,8 @@ def _reduce_ex_by_name(self, proto): class Flag(Enum): """Support for flags"""

+

@@ -628,7 +647,12 @@ class Flag(Enum): """ if not count: return start if start is not None else 1

@classmethod

--- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -3,7 +3,7 @@ import inspect import pydoc import unittest from collections import OrderedDict -from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique +from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto from io import StringIO from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL from test import support @@ -113,6 +113,7 @@ class TestHelpers(unittest.TestCase): '', '', '', '__',): self.assertFalse(enum._is_dunder(s)) +# tests class TestEnum(unittest.TestCase): @@ -1578,6 +1579,61 @@ class TestEnum(unittest.TestCase): self.assertEqual(LabelledList.unprocessed, 1) self.assertEqual(LabelledList(1), LabelledList.unprocessed)

+

+

+

+

+

+

+

+

+ class TestOrder(unittest.TestCase): @@ -1856,7 +1912,6 @@ class TestFlag(unittest.TestCase): test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE) test_pickle_dump_load(self.assertIs, FlagStooges) - def test_containment(self): Perm = self.Perm R, W, X = Perm @@ -1877,6 +1932,24 @@ class TestFlag(unittest.TestCase): self.assertFalse(W in RX) self.assertFalse(X in RW)

+

+

+ + class TestIntFlag(unittest.TestCase): """Tests of the IntFlags."""