issue26981: add _order_ compatibility shim to enum.Enum
This commit is contained in:
parent
3e45875578
commit
e8e61277ff
|
@ -257,7 +257,7 @@ members are not integers (but see `IntEnum`_ below)::
|
||||||
>>> Color.red < Color.blue
|
>>> Color.red < Color.blue
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
File "<stdin>", line 1, in <module>
|
File "<stdin>", line 1, in <module>
|
||||||
TypeError: unorderable types: Color() < Color()
|
TypeError: '<' not supported between instances of 'Color' and 'Color'
|
||||||
|
|
||||||
Equality comparisons are defined though::
|
Equality comparisons are defined though::
|
||||||
|
|
||||||
|
@ -776,3 +776,22 @@ appropriately.
|
||||||
If you wish to change how :class:`Enum` members are looked up you should either
|
If you wish to change how :class:`Enum` members are looked up you should either
|
||||||
write a helper function or a :func:`classmethod` for the :class:`Enum`
|
write a helper function or a :func:`classmethod` for the :class:`Enum`
|
||||||
subclass.
|
subclass.
|
||||||
|
|
||||||
|
To help keep Python 2 / Python 3 code in sync a user-specified :attr:`_order_`,
|
||||||
|
if provided, will be checked to ensure the actual order of the enumeration
|
||||||
|
matches::
|
||||||
|
|
||||||
|
>>> class Color(Enum):
|
||||||
|
... _order_ = 'red green blue'
|
||||||
|
... red = 1
|
||||||
|
... blue = 3
|
||||||
|
... green = 2
|
||||||
|
...
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
TypeError: member order does not match _order_
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
In Python 2 code the :attr:`_order_` attribute is necessary as definition
|
||||||
|
order is lost during class creation.
|
||||||
|
|
15
Lib/enum.py
15
Lib/enum.py
|
@ -64,9 +64,11 @@ class _EnumDict(dict):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if _is_sunder(key):
|
if _is_sunder(key):
|
||||||
|
if key not in ('_order_', ):
|
||||||
raise ValueError('_names_ are reserved for future Enum use')
|
raise ValueError('_names_ are reserved for future Enum use')
|
||||||
elif _is_dunder(key):
|
elif _is_dunder(key):
|
||||||
pass
|
if key == '__order__':
|
||||||
|
key = '_order_'
|
||||||
elif key in self._member_names:
|
elif key in self._member_names:
|
||||||
# descriptor overwriting an enum?
|
# descriptor overwriting an enum?
|
||||||
raise TypeError('Attempted to reuse key: %r' % key)
|
raise TypeError('Attempted to reuse key: %r' % key)
|
||||||
|
@ -106,6 +108,9 @@ class EnumMeta(type):
|
||||||
for name in classdict._member_names:
|
for name in classdict._member_names:
|
||||||
del classdict[name]
|
del classdict[name]
|
||||||
|
|
||||||
|
# adjust the sunders
|
||||||
|
_order_ = classdict.pop('_order_', None)
|
||||||
|
|
||||||
# check for illegal enum names (any others?)
|
# check for illegal enum names (any others?)
|
||||||
invalid_names = set(members) & {'mro', }
|
invalid_names = set(members) & {'mro', }
|
||||||
if invalid_names:
|
if invalid_names:
|
||||||
|
@ -210,6 +215,14 @@ class EnumMeta(type):
|
||||||
if save_new:
|
if save_new:
|
||||||
enum_class.__new_member__ = __new__
|
enum_class.__new_member__ = __new__
|
||||||
enum_class.__new__ = Enum.__new__
|
enum_class.__new__ = Enum.__new__
|
||||||
|
|
||||||
|
# py3 support for definition order (helps keep py2/py3 code in sync)
|
||||||
|
if _order_ is not None:
|
||||||
|
if isinstance(_order_, str):
|
||||||
|
_order_ = _order_.replace(',', ' ').split()
|
||||||
|
if _order_ != enum_class._member_names_:
|
||||||
|
raise TypeError('member order does not match _order_')
|
||||||
|
|
||||||
return enum_class
|
return enum_class
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
|
|
|
@ -1571,6 +1571,68 @@ class TestEnum(unittest.TestCase):
|
||||||
self.assertEqual(LabelledList(1), LabelledList.unprocessed)
|
self.assertEqual(LabelledList(1), LabelledList.unprocessed)
|
||||||
|
|
||||||
|
|
||||||
|
class TestOrder(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_same_members(self):
|
||||||
|
class Color(Enum):
|
||||||
|
_order_ = 'red green blue'
|
||||||
|
red = 1
|
||||||
|
green = 2
|
||||||
|
blue = 3
|
||||||
|
|
||||||
|
def test_same_members_with_aliases(self):
|
||||||
|
class Color(Enum):
|
||||||
|
_order_ = 'red green blue'
|
||||||
|
red = 1
|
||||||
|
green = 2
|
||||||
|
blue = 3
|
||||||
|
verde = green
|
||||||
|
|
||||||
|
def test_same_members_wrong_order(self):
|
||||||
|
with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
|
||||||
|
class Color(Enum):
|
||||||
|
_order_ = 'red green blue'
|
||||||
|
red = 1
|
||||||
|
blue = 3
|
||||||
|
green = 2
|
||||||
|
|
||||||
|
def test_order_has_extra_members(self):
|
||||||
|
with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
|
||||||
|
class Color(Enum):
|
||||||
|
_order_ = 'red green blue purple'
|
||||||
|
red = 1
|
||||||
|
green = 2
|
||||||
|
blue = 3
|
||||||
|
|
||||||
|
def test_order_has_extra_members_with_aliases(self):
|
||||||
|
with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
|
||||||
|
class Color(Enum):
|
||||||
|
_order_ = 'red green blue purple'
|
||||||
|
red = 1
|
||||||
|
green = 2
|
||||||
|
blue = 3
|
||||||
|
verde = green
|
||||||
|
|
||||||
|
def test_enum_has_extra_members(self):
|
||||||
|
with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
|
||||||
|
class Color(Enum):
|
||||||
|
_order_ = 'red green blue'
|
||||||
|
red = 1
|
||||||
|
green = 2
|
||||||
|
blue = 3
|
||||||
|
purple = 4
|
||||||
|
|
||||||
|
def test_enum_has_extra_members_with_aliases(self):
|
||||||
|
with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
|
||||||
|
class Color(Enum):
|
||||||
|
_order_ = 'red green blue'
|
||||||
|
red = 1
|
||||||
|
green = 2
|
||||||
|
blue = 3
|
||||||
|
purple = 4
|
||||||
|
verde = green
|
||||||
|
|
||||||
|
|
||||||
class TestUnique(unittest.TestCase):
|
class TestUnique(unittest.TestCase):
|
||||||
|
|
||||||
def test_unique_clean(self):
|
def test_unique_clean(self):
|
||||||
|
|
|
@ -137,6 +137,9 @@ Library
|
||||||
- Issue #26800: Undocumented support of general bytes-like objects
|
- Issue #26800: Undocumented support of general bytes-like objects
|
||||||
as paths in os functions is now deprecated.
|
as paths in os functions is now deprecated.
|
||||||
|
|
||||||
|
- Issue #26981: Add _order_ compatibility ship to enum.Enum for
|
||||||
|
Python 2/3 code bases.
|
||||||
|
|
||||||
- Issue #27661: Added tzinfo keyword argument to datetime.combine.
|
- Issue #27661: Added tzinfo keyword argument to datetime.combine.
|
||||||
|
|
||||||
- In the curses module, raise an error if window.getstr() or window.instr() is
|
- In the curses module, raise an error if window.getstr() or window.instr() is
|
||||||
|
|
Loading…
Reference in New Issue