[Python-checkins] bpo-44929: [Enum] Fix global repr (GH-27789)

ethanfurman webhook-mailer at python.org
Wed Aug 25 10:24:37 EDT 2021


https://github.com/python/cpython/commit/24da544014f78e6f1440d5ce5c2d14794a020340
commit: 24da544014f78e6f1440d5ce5c2d14794a020340
branch: main
author: Pablo Galindo Salgado <Pablogsal at gmail.com>
committer: ethanfurman <ethan at stoneleaf.us>
date: 2021-08-25T07:24:32-07:00
summary:

bpo-44929: [Enum] Fix global repr (GH-27789)

* Fix typo in __repr__ code

* Add more tests for global int flag reprs

* use last module if multi-module string
  - when an enum's `__module__` contains several module names, only
     use the last one

Co-authored-by: Łukasz Langa <lukasz at langa.pl>
Co-authored-by: Ethan Furman <ethan at stoneleaf.us>

files:
A Misc/NEWS.d/next/Core and Builtins/2021-08-16-23-16-17.bpo-44929.qpMEky.rst
M Lib/enum.py
M Lib/test/test_enum.py

diff --git a/Lib/enum.py b/Lib/enum.py
index 84e3cc17bbc53..0776761ae6e73 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -1390,17 +1390,28 @@ def _power_of_two(value):
     return value == 2 ** _high_bit(value)
 
 def global_enum_repr(self):
-    return '%s.%s' % (self.__class__.__module__, self._name_)
+    """
+    use module.enum_name instead of class.enum_name
+
+    the module is the last module in case of a multi-module name
+    """
+    module = self.__class__.__module__.split('.')[-1]
+    return '%s.%s' % (module, self._name_)
 
 def global_flag_repr(self):
-    module = self.__class__.__module__
+    """
+    use module.flag_name instead of class.flag_name
+
+    the module is the last module in case of a multi-module name
+    """
+    module = self.__class__.__module__.split('.')[-1]
     cls_name = self.__class__.__name__
     if self._name_ is None:
-        return "%x" % (module, cls_name, self._value_)
+        return "%s.%s(0x%x)" % (module, cls_name, self._value_)
     if _is_single_bit(self):
         return '%s.%s' % (module, self._name_)
     if self._boundary_ is not FlagBoundary.KEEP:
-        return module + module.join(self.name.split('|'))
+        return '|'.join(['%s.%s' % (module, name) for name in self.name.split('|')])
     else:
         name = []
         for n in self._name_.split('|'):
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index 116f61e5cf092..52d7756da98bd 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -28,6 +28,9 @@ def load_tests(loader, tests, ignore):
                 ))
     return tests
 
+MODULE = ('test.test_enum', '__main__')[__name__=='__main__']
+SHORT_MODULE = MODULE.split('.')[-1]
+
 # for pickle tests
 try:
     class Stooges(Enum):
@@ -143,6 +146,23 @@ def __init__(self, fget=None, fset=None, fdel=None, doc=None):
     def __get__(self, instance, ownerclass):
         return self.fget(ownerclass)
 
+# for global repr tests
+
+ at enum.global_enum
+class HeadlightsK(IntFlag, boundary=enum.KEEP):
+    OFF_K = 0
+    LOW_BEAM_K = auto()
+    HIGH_BEAM_K = auto()
+    FOG_K = auto()
+
+
+ at enum.global_enum
+class HeadlightsC(IntFlag, boundary=enum.CONFORM):
+    OFF_C = 0
+    LOW_BEAM_C = auto()
+    HIGH_BEAM_C = auto()
+    FOG_C = auto()
+
 
 # tests
 
@@ -3224,6 +3244,34 @@ def test_repr(self):
         self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
         self.assertEqual(repr(Open(~4)), '-5')
 
+    def test_global_repr_keep(self):
+        self.assertEqual(
+                repr(HeadlightsK(0)),
+                '%s.OFF_K' % SHORT_MODULE,
+                )
+        self.assertEqual(
+                repr(HeadlightsK(2**0 + 2**2 + 2**3)),
+                '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|0x8' % {'m': SHORT_MODULE},
+                )
+        self.assertEqual(
+                repr(HeadlightsK(2**3)),
+                '%(m)s.HeadlightsK(0x8)' % {'m': SHORT_MODULE},
+                )
+
+    def test_global_repr_conform1(self):
+        self.assertEqual(
+                repr(HeadlightsC(0)),
+                '%s.OFF_C' % SHORT_MODULE,
+                )
+        self.assertEqual(
+                repr(HeadlightsC(2**0 + 2**2 + 2**3)),
+                '%(m)s.LOW_BEAM_C|%(m)s.FOG_C' % {'m': SHORT_MODULE},
+                )
+        self.assertEqual(
+                repr(HeadlightsC(2**3)),
+                '%(m)s.OFF_C' % {'m': SHORT_MODULE},
+                )
+
     def test_format(self):
         Perm = self.Perm
         self.assertEqual(format(Perm.R, ''), '4')
@@ -4085,7 +4133,7 @@ def setUp(self):
     def test_convert_value_lookup_priority(self):
         test_type = enum.IntEnum._convert_(
                 'UnittestConvert',
-                ('test.test_enum', '__main__')[__name__=='__main__'],
+                MODULE,
                 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
@@ -4095,7 +4143,7 @@ def test_convert_value_lookup_priority(self):
     def test_convert(self):
         test_type = enum.IntEnum._convert_(
                 'UnittestConvert',
-                ('test.test_enum', '__main__')[__name__=='__main__'],
+                MODULE,
                 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,
@@ -4115,7 +4163,7 @@ def test_convert_warn(self):
         with self.assertWarns(DeprecationWarning):
             enum.IntEnum._convert(
                 'UnittestConvert',
-                ('test.test_enum', '__main__')[__name__=='__main__'],
+                MODULE,
                 filter=lambda x: x.startswith('CONVERT_TEST_'))
 
     @unittest.skipUnless(python_version >= (3, 9),
@@ -4124,16 +4172,15 @@ def test_convert_raise(self):
         with self.assertRaises(AttributeError):
             enum.IntEnum._convert(
                 'UnittestConvert',
-                ('test.test_enum', '__main__')[__name__=='__main__'],
+                MODULE,
                 filter=lambda x: x.startswith('CONVERT_TEST_'))
 
     def test_convert_repr_and_str(self):
-        module = ('test.test_enum', '__main__')[__name__=='__main__']
         test_type = enum.IntEnum._convert_(
                 'UnittestConvert',
-                module,
+                MODULE,
                 filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
-        self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
+        self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % SHORT_MODULE)
         self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
         self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
 
@@ -4151,7 +4198,7 @@ def setUp(self):
     def test_convert(self):
         test_type = enum.StrEnum._convert_(
                 'UnittestConvert',
-                ('test.test_enum', '__main__')[__name__=='__main__'],
+                MODULE,
                 filter=lambda x: x.startswith('CONVERT_STR_'))
         # Ensure that test_type has all of the desired names and values.
         self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
@@ -4162,12 +4209,11 @@ def test_convert(self):
                          [], msg='Names other than CONVERT_STR_* found.')
 
     def test_convert_repr_and_str(self):
-        module = ('test.test_enum', '__main__')[__name__=='__main__']
         test_type = enum.StrEnum._convert_(
                 'UnittestConvert',
-                module,
+                MODULE,
                 filter=lambda x: x.startswith('CONVERT_STR_'))
-        self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
+        self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE)
         self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
         self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
 
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-08-16-23-16-17.bpo-44929.qpMEky.rst b/Misc/NEWS.d/next/Core and Builtins/2021-08-16-23-16-17.bpo-44929.qpMEky.rst
new file mode 100644
index 0000000000000..e883e031a4afd
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-08-16-23-16-17.bpo-44929.qpMEky.rst	
@@ -0,0 +1,2 @@
+Fix some edge cases of ``enum.Flag`` string representation in the REPL.
+Patch by Pablo Galindo.



More information about the Python-checkins mailing list