diff options
author | Ethan Furman <ethan@stoneleaf.us> | 2021-04-12 19:16:46 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-12 19:16:46 (GMT) |
commit | f396a1a940f8608a4be2a9ac4ef82e37c198ecd3 (patch) | |
tree | 275a06738d25429b80a6753d48c0428e79656092 | |
parent | 04425a922b598d03770619b0c658ee9874113550 (diff) | |
download | cpython-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.py | 31 | ||||
-rw-r--r-- | Lib/test/test_enum.py | 32 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2021-04-11-21-10-57.bpo-42248.pedB1E.rst | 1 |
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 |