Skip to content

Commit 9ab4dd4

Browse files
authored
[3.9] bpo-42851: [Enum] remove brittle __init_subclass__ support (GH-24154) (GH-24155)
Solution to support calls to `__init_subclass__` with members defined is too brittle and breaks with certain mixins.. (cherry picked from commit a581a86)
1 parent 8c3914a commit 9ab4dd4

File tree

3 files changed

+2
-76
lines changed

3 files changed

+2
-76
lines changed

Lib/enum.py

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,6 @@
99
]
1010

1111

12-
class _NoInitSubclass:
13-
"""
14-
temporary base class to suppress calling __init_subclass__
15-
"""
16-
@classmethod
17-
def __init_subclass__(cls, **kwds):
18-
pass
19-
2012
def _is_descriptor(obj):
2113
"""
2214
Returns True if obj is a descriptor, False otherwise.
@@ -219,22 +211,7 @@ def __new__(metacls, cls, bases, classdict, **kwds):
219211
if '__doc__' not in classdict:
220212
classdict['__doc__'] = 'An enumeration.'
221213

222-
# postpone calling __init_subclass__
223-
if '__init_subclass__' in classdict and classdict['__init_subclass__'] is None:
224-
raise TypeError('%s.__init_subclass__ cannot be None')
225-
# remove current __init_subclass__ so previous one can be found with getattr
226-
new_init_subclass = classdict.pop('__init_subclass__', None)
227-
# create our new Enum type
228-
if bases:
229-
bases = (_NoInitSubclass, ) + bases
230-
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
231-
enum_class.__bases__ = enum_class.__bases__[1:] #or (object, )
232-
else:
233-
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
234-
old_init_subclass = getattr(enum_class, '__init_subclass__', None)
235-
# and restore the new one (if there was one)
236-
if new_init_subclass is not None:
237-
enum_class.__init_subclass__ = classmethod(new_init_subclass)
214+
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
238215
enum_class._member_names_ = [] # names in definition order
239216
enum_class._member_map_ = {} # name->value map
240217
enum_class._member_type_ = member_type
@@ -346,9 +323,6 @@ def __new__(metacls, cls, bases, classdict, **kwds):
346323
if _order_ != enum_class._member_names_:
347324
raise TypeError('member order does not match _order_')
348325

349-
# finally, call parents' __init_subclass__
350-
if Enum is not None and old_init_subclass is not None:
351-
old_init_subclass(**kwds)
352326
return enum_class
353327

354328
def __bool__(self):
@@ -726,9 +700,6 @@ def _generate_next_value_(name, start, count, last_values):
726700
else:
727701
return start
728702

729-
def __init_subclass__(cls, **kwds):
730-
super().__init_subclass__(**kwds)
731-
732703
@classmethod
733704
def _missing_(cls, value):
734705
return None

Lib/test/test_enum.py

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,52 +2065,6 @@ class Private(Enum):
20652065
except ValueError:
20662066
pass
20672067

2068-
def test_init_subclass_calling(self):
2069-
class MyEnum(Enum):
2070-
def __init_subclass__(cls, **kwds):
2071-
super(MyEnum, cls).__init_subclass__(**kwds)
2072-
self.assertFalse(cls.__dict__.get('_test', False))
2073-
cls._test1 = 'MyEnum'
2074-
#
2075-
class TheirEnum(MyEnum):
2076-
def __init_subclass__(cls, **kwds):
2077-
super().__init_subclass__(**kwds)
2078-
cls._test2 = 'TheirEnum'
2079-
class WhoseEnum(TheirEnum):
2080-
def __init_subclass__(cls, **kwds):
2081-
pass
2082-
class NoEnum(WhoseEnum):
2083-
ONE = 1
2084-
self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2085-
self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2086-
self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2087-
self.assertFalse(NoEnum.__dict__.get('_test1', False))
2088-
self.assertFalse(NoEnum.__dict__.get('_test2', False))
2089-
#
2090-
class OurEnum(MyEnum):
2091-
def __init_subclass__(cls, **kwds):
2092-
cls._test2 = 'OurEnum'
2093-
class WhereEnum(OurEnum):
2094-
def __init_subclass__(cls, **kwds):
2095-
pass
2096-
class NeverEnum(WhereEnum):
2097-
ONE = 'one'
2098-
self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2099-
self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2100-
self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2101-
self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2102-
self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2103-
2104-
def test_init_subclass_parameter(self):
2105-
class multiEnum(Enum):
2106-
def __init_subclass__(cls, multi):
2107-
for member in cls:
2108-
member._as_parameter_ = multi * member.value
2109-
class E(multiEnum, multi=3):
2110-
A = 1
2111-
B = 2
2112-
self.assertEqual(E.A._as_parameter_, 3)
2113-
self.assertEqual(E.B._as_parameter_, 6)
21142068

21152069
class TestOrder(unittest.TestCase):
21162070

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
remove __init_subclass__ support for Enum members

0 commit comments

Comments
 (0)