signal, socket, and ssl module IntEnum constant name lookups now return a

consistent name for values having multiple names.  Ex: signal.Signals(6)
now refers to itself as signal.SIGALRM rather than flipping between that
and signal.SIGIOT based on the interpreter's hash randomization seed.

This helps finish issue27167.
parent 16931c35
......@@ -550,8 +550,14 @@ class Enum(metaclass=EnumMeta):
source = vars(source)
else:
source = module_globals
members = {name: value for name, value in source.items()
if filter(name)}
# We use an OrderedDict of sorted source keys so that the
# _value2member_map is populated in the same order every time
# for a consistent reverse mapping of number to name when there
# are multiple names for the same number rather than varying
# between runs due to hash randomization of the module dictionary.
members = OrderedDict((name, source[name])
for name in sorted(source.keys())
if filter(name))
cls = cls(name, members, module=module)
cls.__reduce_ex__ = _reduce_ex_by_name
module_globals.update(cls.__members__)
......
......@@ -1768,5 +1768,41 @@ class MiscTestCase(unittest.TestCase):
support.check__all__(self, enum)
# These are unordered here on purpose to ensure that declaration order
# makes no difference.
CONVERT_TEST_NAME_D = 5
CONVERT_TEST_NAME_C = 5
CONVERT_TEST_NAME_B = 5
CONVERT_TEST_NAME_A = 5 # This one should sort first.
CONVERT_TEST_NAME_E = 5
CONVERT_TEST_NAME_F = 5
class TestIntEnumConvert(unittest.TestCase):
def test_convert_value_lookup_priority(self):
test_type = enum.IntEnum._convert(
'UnittestConvert', 'test.test_enum',
filter=lambda x: x.startswith('CONVERT_TEST_'))
# We don't want the reverse lookup value to vary when there are
# multiple possible names for a given value. It should always
# report the first lexigraphical name in that case.
self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
def test_convert(self):
test_type = enum.IntEnum._convert(
'UnittestConvert', 'test.test_enum',
filter=lambda x: x.startswith('CONVERT_TEST_'))
# Ensure that test_type has all of the desired names and values.
self.assertEqual(test_type.CONVERT_TEST_NAME_F,
test_type.CONVERT_TEST_NAME_A)
self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
# Ensure that test_type only picked up names matching the filter.
self.assertEqual([name for name in dir(test_type)
if name[0:2] not in ('CO', '__')],
[], msg='Names other than CONVERT_TEST_* found.')
if __name__ == '__main__':
unittest.main()
......@@ -27,6 +27,11 @@ Core and Builtins
Library
-------
- signal, socket, and ssl module IntEnum constant name lookups now return a
consistent name for values having multiple names. Ex: signal.Signals(6)
now refers to itself as signal.SIGALRM rather than flipping between that
and signal.SIGIOT based on the interpreter's hash randomization seed.
- Issue #27167: Clarify the subprocess.CalledProcessError error message text
when the child process died due to a signal.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment