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__)
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()
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.