Skip to content

bpo-42851: [Enum] remove brittle __init_subclass__ support #24154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 1 addition & 30 deletions Lib/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,6 @@
]


class _NoInitSubclass:
"""
temporary base class to suppress calling __init_subclass__
"""
@classmethod
def __init_subclass__(cls, **kwds):
pass

def _is_descriptor(obj):
"""
Returns True if obj is a descriptor, False otherwise.
Expand Down Expand Up @@ -227,22 +219,7 @@ def __new__(metacls, cls, bases, classdict, **kwds):
if '__doc__' not in classdict:
classdict['__doc__'] = 'An enumeration.'

# postpone calling __init_subclass__
if '__init_subclass__' in classdict and classdict['__init_subclass__'] is None:
raise TypeError('%s.__init_subclass__ cannot be None')
# remove current __init_subclass__ so previous one can be found with getattr
new_init_subclass = classdict.pop('__init_subclass__', None)
# create our new Enum type
if bases:
bases = (_NoInitSubclass, ) + bases
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
enum_class.__bases__ = enum_class.__bases__[1:] #or (object, )
else:
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
old_init_subclass = getattr(enum_class, '__init_subclass__', None)
# and restore the new one (if there was one)
if new_init_subclass is not None:
enum_class.__init_subclass__ = classmethod(new_init_subclass)
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
enum_class._member_names_ = [] # names in definition order
enum_class._member_map_ = {} # name->value map
enum_class._member_type_ = member_type
Expand Down Expand Up @@ -354,9 +331,6 @@ def __new__(metacls, cls, bases, classdict, **kwds):
if _order_ != enum_class._member_names_:
raise TypeError('member order does not match _order_')

# finally, call parents' __init_subclass__
if Enum is not None and old_init_subclass is not None:
old_init_subclass(**kwds)
return enum_class

def __bool__(self):
Expand Down Expand Up @@ -734,9 +708,6 @@ def _generate_next_value_(name, start, count, last_values):
else:
return start

def __init_subclass__(cls, **kwds):
super().__init_subclass__(**kwds)

@classmethod
def _missing_(cls, value):
return None
Expand Down
45 changes: 0 additions & 45 deletions Lib/test/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -2119,52 +2119,7 @@ class ThirdFailedStrEnum(StrEnum):
one = '1'
two = b'2', 'ascii', 9

def test_init_subclass_calling(self):
class MyEnum(Enum):
def __init_subclass__(cls, **kwds):
super(MyEnum, cls).__init_subclass__(**kwds)
self.assertFalse(cls.__dict__.get('_test', False))
cls._test1 = 'MyEnum'
#
class TheirEnum(MyEnum):
def __init_subclass__(cls, **kwds):
super().__init_subclass__(**kwds)
cls._test2 = 'TheirEnum'
class WhoseEnum(TheirEnum):
def __init_subclass__(cls, **kwds):
pass
class NoEnum(WhoseEnum):
ONE = 1
self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
self.assertFalse(NoEnum.__dict__.get('_test1', False))
self.assertFalse(NoEnum.__dict__.get('_test2', False))
#
class OurEnum(MyEnum):
def __init_subclass__(cls, **kwds):
cls._test2 = 'OurEnum'
class WhereEnum(OurEnum):
def __init_subclass__(cls, **kwds):
pass
class NeverEnum(WhereEnum):
ONE = 'one'
self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
self.assertFalse(WhereEnum.__dict__.get('_test1', False))
self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
self.assertFalse(NeverEnum.__dict__.get('_test1', False))
self.assertFalse(NeverEnum.__dict__.get('_test2', False))

def test_init_subclass_parameter(self):
class multiEnum(Enum):
def __init_subclass__(cls, multi):
for member in cls:
member._as_parameter_ = multi * member.value
class E(multiEnum, multi=3):
A = 1
B = 2
self.assertEqual(E.A._as_parameter_, 3)
self.assertEqual(E.B._as_parameter_, 6)

@unittest.skipUnless(
sys.version_info[:2] == (3, 9),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
remove __init_subclass__ support for Enum members