Skip to content

Commit a581a86

Browse files
authored
bpo-42851: [Enum] remove brittle __init_subclass__ support (GH-24154)
Solution to support calls to `__init_subclass__` with members defined is too brittle and breaks with certain mixins.
1 parent 8643345 commit a581a86

File tree

3 files changed

+2
-75
lines changed

3 files changed

+2
-75
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.
@@ -227,22 +219,7 @@ def __new__(metacls, cls, bases, classdict, **kwds):
227219
if '__doc__' not in classdict:
228220
classdict['__doc__'] = 'An enumeration.'
229221

230-
# postpone calling __init_subclass__
231-
if '__init_subclass__' in classdict and classdict['__init_subclass__'] is None:
232-
raise TypeError('%s.__init_subclass__ cannot be None')
233-
# remove current __init_subclass__ so previous one can be found with getattr
234-
new_init_subclass = classdict.pop('__init_subclass__', None)
235-
# create our new Enum type
236-
if bases:
237-
bases = (_NoInitSubclass, ) + bases
238-
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
239-
enum_class.__bases__ = enum_class.__bases__[1:] #or (object, )
240-
else:
241-
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
242-
old_init_subclass = getattr(enum_class, '__init_subclass__', None)
243-
# and restore the new one (if there was one)
244-
if new_init_subclass is not None:
245-
enum_class.__init_subclass__ = classmethod(new_init_subclass)
222+
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
246223
enum_class._member_names_ = [] # names in definition order
247224
enum_class._member_map_ = {} # name->value map
248225
enum_class._member_type_ = member_type
@@ -354,9 +331,6 @@ def __new__(metacls, cls, bases, classdict, **kwds):
354331
if _order_ != enum_class._member_names_:
355332
raise TypeError('member order does not match _order_')
356333

357-
# finally, call parents' __init_subclass__
358-
if Enum is not None and old_init_subclass is not None:
359-
old_init_subclass(**kwds)
360334
return enum_class
361335

362336
def __bool__(self):
@@ -734,9 +708,6 @@ def _generate_next_value_(name, start, count, last_values):
734708
else:
735709
return start
736710

737-
def __init_subclass__(cls, **kwds):
738-
super().__init_subclass__(**kwds)
739-
740711
@classmethod
741712
def _missing_(cls, value):
742713
return None

Lib/test/test_enum.py

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,52 +2119,7 @@ class ThirdFailedStrEnum(StrEnum):
21192119
one = '1'
21202120
two = b'2', 'ascii', 9
21212121

2122-
def test_init_subclass_calling(self):
2123-
class MyEnum(Enum):
2124-
def __init_subclass__(cls, **kwds):
2125-
super(MyEnum, cls).__init_subclass__(**kwds)
2126-
self.assertFalse(cls.__dict__.get('_test', False))
2127-
cls._test1 = 'MyEnum'
2128-
#
2129-
class TheirEnum(MyEnum):
2130-
def __init_subclass__(cls, **kwds):
2131-
super().__init_subclass__(**kwds)
2132-
cls._test2 = 'TheirEnum'
2133-
class WhoseEnum(TheirEnum):
2134-
def __init_subclass__(cls, **kwds):
2135-
pass
2136-
class NoEnum(WhoseEnum):
2137-
ONE = 1
2138-
self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2139-
self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2140-
self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2141-
self.assertFalse(NoEnum.__dict__.get('_test1', False))
2142-
self.assertFalse(NoEnum.__dict__.get('_test2', False))
2143-
#
2144-
class OurEnum(MyEnum):
2145-
def __init_subclass__(cls, **kwds):
2146-
cls._test2 = 'OurEnum'
2147-
class WhereEnum(OurEnum):
2148-
def __init_subclass__(cls, **kwds):
2149-
pass
2150-
class NeverEnum(WhereEnum):
2151-
ONE = 'one'
2152-
self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2153-
self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2154-
self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2155-
self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2156-
self.assertFalse(NeverEnum.__dict__.get('_test2', False))
21572122

2158-
def test_init_subclass_parameter(self):
2159-
class multiEnum(Enum):
2160-
def __init_subclass__(cls, multi):
2161-
for member in cls:
2162-
member._as_parameter_ = multi * member.value
2163-
class E(multiEnum, multi=3):
2164-
A = 1
2165-
B = 2
2166-
self.assertEqual(E.A._as_parameter_, 3)
2167-
self.assertEqual(E.B._as_parameter_, 6)
21682123

21692124
@unittest.skipUnless(
21702125
sys.version_info[:2] == (3, 9),
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)