bpo-40025: Require _generate_next_value_ to be defined before members (GH-19098)

require `_generate_next_value_` to be defined before members
This commit is contained in:
Ethan Onstott 2020-04-28 13:20:55 -04:00 committed by GitHub
parent a42ca74fa3
commit d9a43e20fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 21 additions and 0 deletions

View file

@ -273,6 +273,10 @@ overridden::
the next :class:`int` in sequence with the last :class:`int` provided, but the next :class:`int` in sequence with the last :class:`int` provided, but
the way it does this is an implementation detail and may change. the way it does this is an implementation detail and may change.
.. note::
The :meth:`_generate_next_value_` method must be defined before any members.
Iteration Iteration
--------- ---------

View file

@ -60,6 +60,7 @@ class _EnumDict(dict):
self._member_names = [] self._member_names = []
self._last_values = [] self._last_values = []
self._ignore = [] self._ignore = []
self._auto_called = False
def __setitem__(self, key, value): def __setitem__(self, key, value):
"""Changes anything not dundered or not a descriptor. """Changes anything not dundered or not a descriptor.
@ -77,6 +78,9 @@ class _EnumDict(dict):
): ):
raise ValueError('_names_ are reserved for future Enum use') raise ValueError('_names_ are reserved for future Enum use')
if key == '_generate_next_value_': if key == '_generate_next_value_':
# check if members already defined as auto()
if self._auto_called:
raise TypeError("_generate_next_value_ must be defined before members")
setattr(self, '_generate_next_value', value) setattr(self, '_generate_next_value', value)
elif key == '_ignore_': elif key == '_ignore_':
if isinstance(value, str): if isinstance(value, str):
@ -100,6 +104,7 @@ class _EnumDict(dict):
# enum overwriting a descriptor? # enum overwriting a descriptor?
raise TypeError('%r already defined as: %r' % (key, self[key])) raise TypeError('%r already defined as: %r' % (key, self[key]))
if isinstance(value, auto): if isinstance(value, auto):
self._auto_called = True
if value.value == _auto_null: if value.value == _auto_null:
value.value = self._generate_next_value(key, 1, len(self._member_names), self._last_values[:]) value.value = self._generate_next_value(key, 1, len(self._member_names), self._last_values[:])
value = value.value value = value.value

View file

@ -1751,6 +1751,16 @@ class TestEnum(unittest.TestCase):
self.assertEqual(Color.blue.value, 2) self.assertEqual(Color.blue.value, 2)
self.assertEqual(Color.green.value, 3) self.assertEqual(Color.green.value, 3)
def test_auto_order(self):
with self.assertRaises(TypeError):
class Color(Enum):
red = auto()
green = auto()
blue = auto()
def _generate_next_value_(name, start, count, last):
return name
def test_duplicate_auto(self): def test_duplicate_auto(self):
class Dupes(Enum): class Dupes(Enum):
first = primero = auto() first = primero = auto()

View file

@ -1240,6 +1240,7 @@ Bryan Olson
Grant Olson Grant Olson
Furkan Onder Furkan Onder
Koray Oner Koray Oner
Ethan Onstott
Piet van Oostrum Piet van Oostrum
Tomas Oppelstrup Tomas Oppelstrup
Jason Orendorff Jason Orendorff

View file

@ -0,0 +1 @@
Raise TypeError when _generate_next_value_ is defined after members. Patch by Ethan Onstott.