[Python-checkins] [3.9] bpo-42248: [Enum] ensure exceptions raised in ``_missing_`` are released (GH-25350). (GH-25370)

ethanfurman webhook-mailer at python.org
Mon Apr 12 18:03:39 EDT 2021


https://github.com/python/cpython/commit/6379924ecd51e346b42b0293da0f4442a0f67707
commit: 6379924ecd51e346b42b0293da0f4442a0f67707
branch: 3.9
author: Ethan Furman <ethan at stoneleaf.us>
committer: ethanfurman <ethan at stoneleaf.us>
date: 2021-04-12T15:03:29-07:00
summary:

[3.9] bpo-42248: [Enum] ensure exceptions raised in ``_missing_`` are released (GH-25350). (GH-25370)

(cherry picked from commit 8c14f5a787b21d5a1eae5d5ee981431d1c0e055f)

Co-authored-by: Ethan Furman <ethan at stoneleaf.us>

files:
A Misc/NEWS.d/next/Library/2021-04-11-21-10-57.bpo-42248.pedB1E.rst
M Lib/enum.py
M Lib/test/test_enum.py

diff --git a/Lib/enum.py b/Lib/enum.py
index 1fddb1c75e8be..be74796a8a0ce 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -669,19 +669,24 @@ def __new__(cls, value):
         except Exception as e:
             exc = e
             result = None
-        if isinstance(result, cls):
-            return result
-        else:
-            ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
-            if result is None and exc is None:
-                raise ve_exc
-            elif exc is None:
-                exc = TypeError(
-                        'error in %s._missing_: returned %r instead of None or a valid member'
-                        % (cls.__name__, result)
-                        )
-            exc.__context__ = ve_exc
-            raise exc
+        try:
+            if isinstance(result, cls):
+                return result
+            else:
+                ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
+                if result is None and exc is None:
+                    raise ve_exc
+                elif exc is None:
+                    exc = TypeError(
+                            'error in %s._missing_: returned %r instead of None or a valid member'
+                            % (cls.__name__, result)
+                            )
+                exc.__context__ = ve_exc
+                raise exc
+        finally:
+            # ensure all variables that could hold an exception are destroyed
+            exc = None
+            ve_exc = None
 
     def _generate_next_value_(name, start, count, last_values):
         """
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index 4e22986325521..fc2d61d59cd4b 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -1897,6 +1897,38 @@ def _missing_(cls, item):
         else:
             raise Exception('Exception not raised.')
 
+    def test_missing_exceptions_reset(self):
+        import weakref
+        #
+        class TestEnum(enum.Enum):
+            VAL1 = 'val1'
+            VAL2 = 'val2'
+        #
+        class Class1:
+            def __init__(self):
+                # Gracefully handle an exception of our own making
+                try:
+                    raise ValueError()
+                except ValueError:
+                    pass
+        #
+        class Class2:
+            def __init__(self):
+                # Gracefully handle an exception of Enum's making
+                try:
+                    TestEnum('invalid_value')
+                except ValueError:
+                    pass
+        # No strong refs here so these are free to die.
+        class_1_ref = weakref.ref(Class1())
+        class_2_ref = weakref.ref(Class2())
+        #
+        # The exception raised by Enum creates a reference loop and thus
+        # Class2 instances will stick around until the next gargage collection
+        # cycle, unlike Class1.
+        self.assertIs(class_1_ref(), None)
+        self.assertIs(class_2_ref(), None)
+
     def test_multiple_mixin(self):
         class MaxMixin:
             @classproperty
diff --git a/Misc/NEWS.d/next/Library/2021-04-11-21-10-57.bpo-42248.pedB1E.rst b/Misc/NEWS.d/next/Library/2021-04-11-21-10-57.bpo-42248.pedB1E.rst
new file mode 100644
index 0000000000000..0722d35a37a1f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-04-11-21-10-57.bpo-42248.pedB1E.rst
@@ -0,0 +1 @@
+[Enum] ensure exceptions raised in ``_missing__`` are released



More information about the Python-checkins mailing list