From 5bdab641da0afd8aa581dfbde4f82d88d337c4b5 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Fri, 21 Sep 2018 19:03:09 -0700 Subject: bpo-29577: Enum: mixin classes don't mix well with already mixed Enums (GH-9328) * bpo-29577: allow multiple mixin classes --- Lib/enum.py | 50 +++++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 31 deletions(-) (limited to 'Lib/enum.py') diff --git a/Lib/enum.py b/Lib/enum.py index 02405c865b..0ccb30d428 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -480,37 +480,25 @@ class EnumMeta(type): if not bases: return object, Enum - # double check that we are not subclassing a class with existing - # enumeration members; while we're at it, see if any other data - # type has been mixed in so we can use the correct __new__ - member_type = first_enum = None - for base in bases: - if (base is not Enum and - issubclass(base, Enum) and - base._member_names_): - raise TypeError("Cannot extend enumerations") - # base is now the last base in bases - if not issubclass(base, Enum): - raise TypeError("new enumerations must be created as " - "`ClassName([mixin_type,] enum_type)`") - - # get correct mix-in type (either mix-in type of Enum subclass, or - # first base if last base is Enum) - if not issubclass(bases[0], Enum): - member_type = bases[0] # first data type - first_enum = bases[-1] # enum type - else: - for base in bases[0].__mro__: - # most common: (IntEnum, int, Enum, object) - # possible: (, , - # , , - # ) - if issubclass(base, Enum): - if first_enum is None: - first_enum = base - else: - if member_type is None: - member_type = base + def _find_data_type(bases): + for chain in bases: + for base in chain.__mro__: + if base is object: + continue + elif '__new__' in base.__dict__: + if issubclass(base, Enum) and not hasattr(base, '__new_member__'): + continue + return base + + # ensure final parent class is an Enum derivative, find any concrete + # data type, and check that Enum has no members + first_enum = bases[-1] + if not issubclass(first_enum, Enum): + raise TypeError("new enumerations should be created as " + "`EnumName([mixin_type, ...] [data_type,] enum_type)`") + member_type = _find_data_type(bases) or object + if first_enum._member_names_: + raise TypeError("Cannot extend enumerations") return member_type, first_enum -- cgit v1.2.1