summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEthan Furman <ethan@stoneleaf.us>2021-04-12 19:16:46 (GMT)
committerGitHub <noreply@github.com>2021-04-12 19:16:46 (GMT)
commitf396a1a940f8608a4be2a9ac4ef82e37c198ecd3 (patch)
tree275a06738d25429b80a6753d48c0428e79656092
parent04425a922b598d03770619b0c658ee9874113550 (diff)
downloadcpython-f396a1a940f8608a4be2a9ac4ef82e37c198ecd3.zip
cpython-f396a1a940f8608a4be2a9ac4ef82e37c198ecd3.tar.gz
cpython-f396a1a940f8608a4be2a9ac4ef82e37c198ecd3.tar.bz2
[3.8] bpo-42248: [Enum] ensure exceptions raised in ``_missing_`` are released (GH-25350). (GH-25369)
(cherry picked from commit 8c14f5a787b21d5a1eae5d5ee981431d1c0e055f) Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
-rw-r--r--Lib/enum.py31
-rw-r--r--Lib/test/test_enum.py32
-rw-r--r--Misc/NEWS.d/next/Library/2021-04-11-21-10-57.bpo-42248.pedB1E.rst1
3 files changed, 51 insertions, 13 deletions
diff --git a/Lib/enum.py b/Lib/enum.py
index 31afdd3..3d0b179 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -654,19 +654,24 @@ class Enum(metaclass=EnumMeta):
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.__name__))
- 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.__name__))
+ 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 b5e4009..b246163 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -1897,6 +1897,38 @@ class TestEnum(unittest.TestCase):
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 0000000..0722d35
--- /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