]> granicus.if.org Git - python/commitdiff
signal, socket, and ssl module IntEnum constant name lookups now return a
authorGregory P. Smith ext:(%20%5BGoogle%20Inc.%5D) <greg@krypto.org>
Fri, 3 Jun 2016 19:14:52 +0000 (19:14 +0000)
committerGregory P. Smith ext:(%20%5BGoogle%20Inc.%5D) <greg@krypto.org>
Fri, 3 Jun 2016 19:14:52 +0000 (19:14 +0000)
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.

Lib/enum.py
Lib/test/test_enum.py
Misc/NEWS

index c3a0a8b4a98a54095e0de396c3ceec2014761943..99db9e6b7f5a60d0d8a2ac792e81cf8ae5e3c500 100644 (file)
@@ -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__)
index b6cb00fcf4b6f24c6734d738854d61d64e772cab..b1a58557906cf8a534291be66158a1dadd415750 100644 (file)
@@ -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()
index f5a44bd5f9a1417bd8d9eca655edeb1dd6b990d2..a05a4bc9bc1e386c053efd71fc7f96153d3618e5 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.