gh-117663: [Enum] fix _simple_enum's detection of aliases (GH-117664)

This commit is contained in:
Ethan Furman 2024-04-09 11:31:07 -07:00 committed by GitHub
parent d5f1139c79
commit e5521bcca9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 101 additions and 33 deletions

View file

@ -1088,8 +1088,6 @@ class EnumType(type):
setattr(cls, name, member)
# now add to _member_map_ (even aliases)
cls._member_map_[name] = member
#
cls._member_map_[name] = member
EnumMeta = EnumType # keep EnumMeta name for backwards compatibility
@ -1802,20 +1800,31 @@ def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
for name, value in attrs.items():
if isinstance(value, auto) and auto.value is _auto_null:
value = gnv(name, 1, len(member_names), gnv_last_values)
if value in value2member_map or value in unhashable_values:
# an alias to an existing member
enum_class(value)._add_alias_(name)
# create basic member (possibly isolate value for alias check)
if use_args:
if not isinstance(value, tuple):
value = (value, )
member = new_member(enum_class, *value)
value = value[0]
else:
# create the member
if use_args:
if not isinstance(value, tuple):
value = (value, )
member = new_member(enum_class, *value)
value = value[0]
else:
member = new_member(enum_class)
if __new__ is None:
member._value_ = value
member = new_member(enum_class)
if __new__ is None:
member._value_ = value
# now check if alias
try:
contained = value2member_map.get(member._value_)
except TypeError:
contained = None
if member._value_ in unhashable_values:
for m in enum_class:
if m._value_ == member._value_:
contained = m
break
if contained is not None:
# an alias to an existing member
contained._add_alias_(name)
else:
# finish creating member
member._name_ = name
member.__objclass__ = enum_class
member.__init__(value)
@ -1847,24 +1856,31 @@ def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
if value.value is _auto_null:
value.value = gnv(name, 1, len(member_names), gnv_last_values)
value = value.value
try:
contained = value in value2member_map
except TypeError:
contained = value in unhashable_values
if contained:
# an alias to an existing member
enum_class(value)._add_alias_(name)
# create basic member (possibly isolate value for alias check)
if use_args:
if not isinstance(value, tuple):
value = (value, )
member = new_member(enum_class, *value)
value = value[0]
else:
# create the member
if use_args:
if not isinstance(value, tuple):
value = (value, )
member = new_member(enum_class, *value)
value = value[0]
else:
member = new_member(enum_class)
if __new__ is None:
member._value_ = value
member = new_member(enum_class)
if __new__ is None:
member._value_ = value
# now check if alias
try:
contained = value2member_map.get(member._value_)
except TypeError:
contained = None
if member._value_ in unhashable_values:
for m in enum_class:
if m._value_ == member._value_:
contained = m
break
if contained is not None:
# an alias to an existing member
contained._add_alias_(name)
else:
# finish creating member
member._name_ = name
member.__objclass__ = enum_class
member.__init__(value)

View file

@ -5170,7 +5170,57 @@ class TestStdLib(unittest.TestCase):
self.assertIn('python', Unhashable)
self.assertEqual(Unhashable.name.value, 'python')
self.assertEqual(Unhashable.name.name, 'name')
_test_simple_enum(Unhashable, Unhashable)
_test_simple_enum(CheckedUnhashable, Unhashable)
##
class CheckedComplexStatus(IntEnum):
def __new__(cls, value, phrase, description=''):
obj = int.__new__(cls, value)
obj._value_ = value
obj.phrase = phrase
obj.description = description
return obj
CONTINUE = 100, 'Continue', 'Request received, please continue'
PROCESSING = 102, 'Processing'
EARLY_HINTS = 103, 'Early Hints'
SOME_HINTS = 103, 'Some Early Hints'
#
@_simple_enum(IntEnum)
class ComplexStatus:
def __new__(cls, value, phrase, description=''):
obj = int.__new__(cls, value)
obj._value_ = value
obj.phrase = phrase
obj.description = description
return obj
CONTINUE = 100, 'Continue', 'Request received, please continue'
PROCESSING = 102, 'Processing'
EARLY_HINTS = 103, 'Early Hints'
SOME_HINTS = 103, 'Some Early Hints'
_test_simple_enum(CheckedComplexStatus, ComplexStatus)
#
#
class CheckedComplexFlag(IntFlag):
def __new__(cls, value, label):
obj = int.__new__(cls, value)
obj._value_ = value
obj.label = label
return obj
SHIRT = 1, 'upper half'
VEST = 1, 'outer upper half'
PANTS = 2, 'lower half'
self.assertIs(CheckedComplexFlag.SHIRT, CheckedComplexFlag.VEST)
#
@_simple_enum(IntFlag)
class ComplexFlag:
def __new__(cls, value, label):
obj = int.__new__(cls, value)
obj._value_ = value
obj.label = label
return obj
SHIRT = 1, 'upper half'
VEST = 1, 'uppert half'
PANTS = 2, 'lower half'
_test_simple_enum(CheckedComplexFlag, ComplexFlag)
class MiscTestCase(unittest.TestCase):

View file

@ -0,0 +1,2 @@
Fix ``_simple_enum`` to detect aliases when multiple arguments are present
but only one is the member value.