Skip to content

Commit 321acd4

Browse files
miss-islingtonoscar-LT
andauthoredJun 23, 2022
gh-91456: [Enum] Deprecate default auto() behavior with mixed value types (GH-91457)
When used with plain Enum, auto() returns the last numeric value assigned, skipping any incompatible member values (such as strings); starting in 3.13 the default auto() for plain Enums will require all the values to be of compatible types, and will return a new value that is 1 higher than any existing value. Co-authored-by: Ethan Furman <ethan@stoneleaf.us> (cherry picked from commit fb1e950) Co-authored-by: Oscar R <89599049+oscar-LT@users.noreply.github.com>
1 parent 00a25f8 commit 321acd4

File tree

4 files changed

+89
-17
lines changed

4 files changed

+89
-17
lines changed
 

‎Doc/library/enum.rst

+4
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,10 @@ Utilities and Decorators
761761
``_generate_next_value_`` can be overridden to customize the values used by
762762
*auto*.
763763

764+
.. note:: in 3.13 the default ``"generate_next_value_`` will always return
765+
the highest member value incremented by 1, and will fail if any
766+
member is an incompatible type.
767+
764768
.. decorator:: property
765769

766770
A decorator similar to the built-in *property*, but specifically for

‎Lib/enum.py

+26-8
Original file line numberDiff line numberDiff line change
@@ -1218,21 +1218,39 @@ def __new__(cls, value):
12181218
def __init__(self, *args, **kwds):
12191219
pass
12201220

1221-
def _generate_next_value_(name, start, count, last_values):
1221+
def _generate_next_value_(name, start, count, last_value):
12221222
"""
12231223
Generate the next value when not given.
12241224
12251225
name: the name of the member
12261226
start: the initial start value or None
12271227
count: the number of existing members
1228-
last_value: the last value assigned or None
1228+
last_value: the list of values assigned
12291229
"""
1230-
for last_value in reversed(last_values):
1231-
try:
1232-
return last_value + 1
1233-
except TypeError:
1234-
pass
1235-
else:
1230+
if not last_value:
1231+
return start
1232+
try:
1233+
last = last_value[-1]
1234+
last_value.sort()
1235+
if last == last_value[-1]:
1236+
# no difference between old and new methods
1237+
return last + 1
1238+
else:
1239+
# trigger old method (with warning)
1240+
raise TypeError
1241+
except TypeError:
1242+
import warnings
1243+
warnings.warn(
1244+
"In 3.13 the default `auto()`/`_generate_next_value_` will require all values to be sortable and support adding +1\n"
1245+
"and the value returned will be the largest value in the enum incremented by 1",
1246+
DeprecationWarning,
1247+
stacklevel=3,
1248+
)
1249+
for v in last_value:
1250+
try:
1251+
return v + 1
1252+
except TypeError:
1253+
pass
12361254
return start
12371255

12381256
@classmethod

‎Lib/test/test_enum.py

+56-9
Original file line numberDiff line numberDiff line change
@@ -3972,23 +3972,54 @@ class Color(AutoNameEnum):
39723972
self.assertEqual(Color.blue.value, 'blue')
39733973
self.assertEqual(Color.green.value, 'green')
39743974

3975-
def test_auto_garbage(self):
3976-
class Color(Enum):
3977-
red = 'red'
3978-
blue = auto()
3975+
@unittest.skipIf(
3976+
python_version >= (3, 13),
3977+
'mixed types with auto() no longer supported',
3978+
)
3979+
def test_auto_garbage_ok(self):
3980+
with self.assertWarnsRegex(DeprecationWarning, 'will require all values to be sortable'):
3981+
class Color(Enum):
3982+
red = 'red'
3983+
blue = auto()
39793984
self.assertEqual(Color.blue.value, 1)
39803985

3981-
def test_auto_garbage_corrected(self):
3982-
class Color(Enum):
3983-
red = 'red'
3984-
blue = 2
3985-
green = auto()
3986+
@unittest.skipIf(
3987+
python_version >= (3, 13),
3988+
'mixed types with auto() no longer supported',
3989+
)
3990+
def test_auto_garbage_corrected_ok(self):
3991+
with self.assertWarnsRegex(DeprecationWarning, 'will require all values to be sortable'):
3992+
class Color(Enum):
3993+
red = 'red'
3994+
blue = 2
3995+
green = auto()
39863996

39873997
self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
39883998
self.assertEqual(Color.red.value, 'red')
39893999
self.assertEqual(Color.blue.value, 2)
39904000
self.assertEqual(Color.green.value, 3)
39914001

4002+
@unittest.skipIf(
4003+
python_version < (3, 13),
4004+
'mixed types with auto() will raise in 3.13',
4005+
)
4006+
def test_auto_garbage_fail(self):
4007+
with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'):
4008+
class Color(Enum):
4009+
red = 'red'
4010+
blue = auto()
4011+
4012+
@unittest.skipIf(
4013+
python_version < (3, 13),
4014+
'mixed types with auto() will raise in 3.13',
4015+
)
4016+
def test_auto_garbage_corrected_fail(self):
4017+
with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'):
4018+
class Color(Enum):
4019+
red = 'red'
4020+
blue = 2
4021+
green = auto()
4022+
39924023
def test_auto_order(self):
39934024
with self.assertRaises(TypeError):
39944025
class Color(Enum):
@@ -4010,6 +4041,22 @@ def _generate_next_value_(name, start, count, last):
40104041
self.assertEqual(Color.red.value, 'pathological case')
40114042
self.assertEqual(Color.blue.value, 'blue')
40124043

4044+
@unittest.skipIf(
4045+
python_version < (3, 13),
4046+
'auto() will return highest value + 1 in 3.13',
4047+
)
4048+
def test_auto_with_aliases(self):
4049+
class Color(Enum):
4050+
red = auto()
4051+
blue = auto()
4052+
oxford = blue
4053+
crimson = red
4054+
green = auto()
4055+
self.assertIs(Color.crimson, Color.red)
4056+
self.assertIs(Color.oxford, Color.blue)
4057+
self.assertIsNot(Color.green, Color.red)
4058+
self.assertIsNot(Color.green, Color.blue)
4059+
40134060
def test_duplicate_auto(self):
40144061
class Dupes(Enum):
40154062
first = primero = auto()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Deprecate current default auto() behavior: In 3.13 the default will be for
2+
for auto() to always return the largest member value incremented by
3+
1, and to raise if incompatible value types are used.

0 commit comments

Comments
 (0)
Please sign in to comment.