10
10
from collections import OrderedDict
11
11
12
12
13
- __all__ = ['EnumMeta' , 'Enum' , 'IntEnum' , 'Flag' , 'IntFlag' , 'unique' ]
13
+ __all__ = [
14
+ 'EnumMeta' ,
15
+ 'Enum' , 'IntEnum' , 'Flag' , 'IntFlag' ,
16
+ 'auto' , 'unique' ,
17
+ ]
14
18
15
19
16
20
def _is_descriptor (obj ):
@@ -36,14 +40,19 @@ def _is_sunder(name):
36
40
name [- 2 :- 1 ] != '_' and
37
41
len (name ) > 2 )
38
42
39
-
40
43
def _make_class_unpicklable (cls ):
41
44
"""Make the given class un-picklable."""
42
45
def _break_on_call_reduce (self , proto ):
43
46
raise TypeError ('%r cannot be pickled' % self )
44
47
cls .__reduce_ex__ = _break_on_call_reduce
45
48
cls .__module__ = '<unknown>'
46
49
50
+ class auto :
51
+ """
52
+ Instances are replaced with an appropriate value in Enum class suites.
53
+ """
54
+ pass
55
+
47
56
48
57
class _EnumDict (dict ):
49
58
"""Track enum member order and ensure member names are not reused.
@@ -55,6 +64,7 @@ class _EnumDict(dict):
55
64
def __init__ (self ):
56
65
super ().__init__ ()
57
66
self ._member_names = []
67
+ self ._last_values = []
58
68
59
69
def __setitem__ (self , key , value ):
60
70
"""Changes anything not dundered or not a descriptor.
@@ -71,6 +81,8 @@ def __setitem__(self, key, value):
71
81
'_generate_next_value_' , '_missing_' ,
72
82
):
73
83
raise ValueError ('_names_ are reserved for future Enum use' )
84
+ if key == '_generate_next_value_' :
85
+ setattr (self , '_generate_next_value' , value )
74
86
elif _is_dunder (key ):
75
87
if key == '__order__' :
76
88
key = '_order_'
@@ -81,11 +93,13 @@ def __setitem__(self, key, value):
81
93
if key in self :
82
94
# enum overwriting a descriptor?
83
95
raise TypeError ('%r already defined as: %r' % (key , self [key ]))
96
+ if isinstance (value , auto ):
97
+ value = self ._generate_next_value (key , 1 , len (self ._member_names ), self ._last_values [:])
84
98
self ._member_names .append (key )
99
+ self ._last_values .append (value )
85
100
super ().__setitem__ (key , value )
86
101
87
102
88
-
89
103
# Dummy value for Enum as EnumMeta explicitly checks for it, but of course
90
104
# until EnumMeta finishes running the first time the Enum class doesn't exist.
91
105
# This is also why there are checks in EnumMeta like `if Enum is not None`
@@ -366,10 +380,11 @@ def _create_(cls, class_name, names=None, *, module=None, qualname=None, type=No
366
380
names = names .replace (',' , ' ' ).split ()
367
381
if isinstance (names , (tuple , list )) and isinstance (names [0 ], str ):
368
382
original_names , names = names , []
369
- last_value = None
383
+ last_values = []
370
384
for count , name in enumerate (original_names ):
371
- last_value = first_enum ._generate_next_value_ (name , start , count , last_value )
372
- names .append ((name , last_value ))
385
+ value = first_enum ._generate_next_value_ (name , start , count , last_values [:])
386
+ last_values .append (value )
387
+ names .append ((name , value ))
373
388
374
389
# Here, names is either an iterable of (name, value) or a mapping.
375
390
for item in names :
@@ -514,11 +529,15 @@ def __new__(cls, value):
514
529
# still not found -- try _missing_ hook
515
530
return cls ._missing_ (value )
516
531
517
- @staticmethod
518
- def _generate_next_value_ (name , start , count , last_value ):
519
- if not count :
532
+ def _generate_next_value_ (name , start , count , last_values ):
533
+ for last_value in reversed (last_values ):
534
+ try :
535
+ return last_value + 1
536
+ except TypeError :
537
+ pass
538
+ else :
520
539
return start
521
- return last_value + 1
540
+
522
541
@classmethod
523
542
def _missing_ (cls , value ):
524
543
raise ValueError ("%r is not a valid %s" % (value , cls .__name__ ))
@@ -616,8 +635,8 @@ def _reduce_ex_by_name(self, proto):
616
635
617
636
class Flag (Enum ):
618
637
"""Support for flags"""
619
- @ staticmethod
620
- def _generate_next_value_ (name , start , count , last_value ):
638
+
639
+ def _generate_next_value_ (name , start , count , last_values ):
621
640
"""
622
641
Generate the next value when not given.
623
642
@@ -628,7 +647,12 @@ def _generate_next_value_(name, start, count, last_value):
628
647
"""
629
648
if not count :
630
649
return start if start is not None else 1
631
- high_bit = _high_bit (last_value )
650
+ for last_value in reversed (last_values ):
651
+ try :
652
+ high_bit = _high_bit (last_value )
653
+ break
654
+ except TypeError :
655
+ raise TypeError ('Invalid Flag value: %r' % last_value ) from None
632
656
return 2 ** (high_bit + 1 )
633
657
634
658
@classmethod
0 commit comments