Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
deprecate current behavior
  • Loading branch information
ethanfurman committed Jun 23, 2022
commit d65aaf4d3a092d32059dc7d978a2aab685b78cb6
4 changes: 4 additions & 0 deletions Doc/library/enum.rst
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,10 @@ Utilities and Decorators
``_generate_next_value_`` can be overridden to customize the values used by
*auto*.

.. note:: in 3.13 the default ``"generate_next_value_`` will always return
the highest member value incremented by 1, and will fail if any
member is an incompatible type.

.. decorator:: property

A decorator similar to the built-in *property*, but specifically for
Expand Down
41 changes: 26 additions & 15 deletions Lib/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -1205,28 +1205,39 @@ def __new__(cls, value):
def __init__(self, *args, **kwds):
pass

def _generate_next_value_(name, start, count, last_values):
def _generate_next_value_(name, start, count, last_value):
"""
Generate the next value when not given.

name: the name of the member
start: the initial start value or None
count: the number of existing members
last_values: the list of values assigned
last_value: the list of values assigned
"""

# Filter funciton to deal with last_values lists of mixed types
def test_incrementable(n):
try:
n + 1
return True
except TypeError:
return False

checked_last_values = sorted(filter(test_incrementable, last_values))
if checked_last_values:
return checked_last_values[-1] + 1
else:
if not last_value:
return start
try:
last = last_value[-1]
last_value.sort()
if last == last_value[-1]:
# no difference between old and new methods
return last + 1
else:
# trigger old method (with warning)
raise TypeError
except TypeError:
import warnings
warnings.warn(
"In 3.13 the default `auto()`/`_generate_next_value_` will require all values to be sortable and support adding +1\n"
"and the value returned will be the largest value in the enum incremented by 1",
DeprecationWarning,
stacklevel=3,
)
for v in last_value:
try:
return v + 1
except TypeError:
pass
return start

@classmethod
Expand Down
53 changes: 44 additions & 9 deletions Lib/test/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -3953,23 +3953,54 @@ class Color(AutoNameEnum):
self.assertEqual(Color.blue.value, 'blue')
self.assertEqual(Color.green.value, 'green')

def test_auto_garbage(self):
class Color(Enum):
red = 'red'
blue = auto()
@unittest.skipIf(
python_version >= (3, 13),
'mixed types with auto() no longer supported',
)
def test_auto_garbage_ok(self):
with self.assertWarnsRegex(DeprecationWarning, 'will require all values to be sortable'):
class Color(Enum):
red = 'red'
blue = auto()
self.assertEqual(Color.blue.value, 1)

def test_auto_garbage_corrected(self):
class Color(Enum):
red = 'red'
blue = 2
green = auto()
@unittest.skipIf(
python_version >= (3, 13),
'mixed types with auto() no longer supported',
)
def test_auto_garbage_corrected_ok(self):
with self.assertWarnsRegex(DeprecationWarning, 'will require all values to be sortable'):
class Color(Enum):
red = 'red'
blue = 2
green = auto()

self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
self.assertEqual(Color.red.value, 'red')
self.assertEqual(Color.blue.value, 2)
self.assertEqual(Color.green.value, 3)

@unittest.skipIf(
python_version < (3, 13),
'mixed types with auto() will raise in 3.13',
)
def test_auto_garbage_fail(self):
with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'):
class Color(Enum):
red = 'red'
blue = auto()

@unittest.skipIf(
python_version < (3, 13),
'mixed types with auto() will raise in 3.13',
)
def test_auto_garbage_corrected_fail(self):
with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'):
class Color(Enum):
red = 'red'
blue = 2
green = auto()

def test_auto_order(self):
with self.assertRaises(TypeError):
class Color(Enum):
Expand All @@ -3991,6 +4022,10 @@ def _generate_next_value_(name, start, count, last):
self.assertEqual(Color.red.value, 'pathological case')
self.assertEqual(Color.blue.value, 'blue')

@unittest.skipIf(
python_version < (3, 13),
'auto() will return highest value + 1 in 3.13',
)
def test_auto_with_aliases(self):
class Color(Enum):
red = auto()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Fixed an issue with Enums where the default behavior of auto() was
generating incorrect values following alias assignment
Deprecate current default auto() behavior: In 3.13 the default will be for
for auto() to always return the largest member value incremented by
1, and to raise if incompatible value types are used.