Commit 019f0a0c authored by Ethan Furman's avatar Ethan Furman Committed by GitHub

bpo-34536: raise error for invalid _missing_ results (GH-9147)

* raise exception if _missing_ returns None or invalid type
parent a5d1eb8d
...@@ -585,7 +585,25 @@ class Enum(metaclass=EnumMeta): ...@@ -585,7 +585,25 @@ class Enum(metaclass=EnumMeta):
if member._value_ == value: if member._value_ == value:
return member return member
# still not found -- try _missing_ hook # still not found -- try _missing_ hook
return cls._missing_(value) try:
exc = None
result = cls._missing_(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.__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
def _generate_next_value_(name, start, count, last_values): def _generate_next_value_(name, start, count, last_values):
for last_value in reversed(last_values): for last_value in reversed(last_values):
......
...@@ -3,6 +3,7 @@ import inspect ...@@ -3,6 +3,7 @@ import inspect
import pydoc import pydoc
import sys import sys
import unittest import unittest
import sys
import threading import threading
from collections import OrderedDict from collections import OrderedDict
from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
...@@ -1697,6 +1698,38 @@ class TestEnum(unittest.TestCase): ...@@ -1697,6 +1698,38 @@ class TestEnum(unittest.TestCase):
third = auto() third = auto()
self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes)) self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
def test_missing(self):
class Color(Enum):
red = 1
green = 2
blue = 3
@classmethod
def _missing_(cls, item):
if item == 'three':
return cls.blue
elif item == 'bad return':
# trigger internal error
return 5
elif item == 'error out':
raise ZeroDivisionError
else:
# trigger not found
return None
self.assertIs(Color('three'), Color.blue)
self.assertRaises(ValueError, Color, 7)
try:
Color('bad return')
except TypeError as exc:
self.assertTrue(isinstance(exc.__context__, ValueError))
else:
raise Exception('Exception not raised.')
try:
Color('error out')
except ZeroDivisionError as exc:
self.assertTrue(isinstance(exc.__context__, ValueError))
else:
raise Exception('Exception not raised.')
class TestOrder(unittest.TestCase): class TestOrder(unittest.TestCase):
......
`Enum._missing_`: raise `ValueError` if None returned and `TypeError` if
non-member is returned.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment