mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
bpo-34536: raise error for invalid _missing_ results (GH-9147)
* raise exception if _missing_ returns None or invalid type
This commit is contained in:
parent
a5d1eb8d8b
commit
019f0a0cb8
3 changed files with 54 additions and 1 deletions
20
Lib/enum.py
20
Lib/enum.py
|
@ -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
|
||||||
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):
|
||||||
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):
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
`Enum._missing_`: raise `ValueError` if None returned and `TypeError` if
|
||||||
|
non-member is returned.
|
Loading…
Add table
Add a link
Reference in a new issue