Skip to content

Fix false-positive error on multiple enum base classes #12963

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
Jul 8, 2022
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
19 changes: 17 additions & 2 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1960,14 +1960,29 @@ def is_final_enum_value(self, sym: SymbolTableNode) -> bool:
return False

def check_enum_bases(self, defn: ClassDef) -> None:
"""
Non-enum mixins cannot appear after enum bases; this is disallowed at runtime:

class Foo: ...
class Bar(enum.Enum, Foo): ...

But any number of enum mixins can appear in a class definition
(even if multiple enum bases define __new__). So this is fine:

class Foo(enum.Enum):
def __new__(cls, val): ...
class Bar(enum.Enum):
def __new__(cls, val): ...
class Baz(int, Foo, Bar, enum.Flag): ...
"""
enum_base: Optional[Instance] = None
for base in defn.info.bases:
if enum_base is None and base.type.is_enum:
enum_base = base
continue
elif enum_base is not None:
elif enum_base is not None and not base.type.is_enum:
self.fail(
f'No base classes are allowed after "{enum_base}"',
f'No non-enum mixin classes are allowed after "{enum_base}"',
defn,
)
break
Expand Down
34 changes: 27 additions & 7 deletions test-data/unit/check-enum.test
Original file line number Diff line number Diff line change
Expand Up @@ -1903,6 +1903,14 @@ class Third:
class Mixin:
pass

class EnumWithCustomNew(enum.Enum):
def __new__(cls, val):
pass

class SecondEnumWithCustomNew(enum.Enum):
def __new__(cls, val):
pass

# Correct Enums:

class Correct0(enum.Enum):
Expand All @@ -1920,6 +1928,9 @@ class Correct3(Mixin, enum.Enum):
class RegularClass(Mixin, First, Second):
pass

class Correct5(enum.Enum):
pass

# Correct inheritance:

class _InheritingDataAndMixin(Correct1):
Expand All @@ -1934,42 +1945,51 @@ class _CorrectWithDataAndMixin(Mixin, First, Correct0):
class _CorrectWithMixin(Mixin, Correct2):
pass

class _CorrectMultipleEnumBases(Correct0, Correct5):
pass

class _MultipleEnumBasesAndMixin(int, Correct0, enum.Flag):
pass

class _MultipleEnumBasesWithCustomNew(int, EnumWithCustomNew, SecondEnumWithCustomNew):
pass

# Wrong Enums:

class TwoDataTypesViaInheritance(Second, Correct2): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Correct2"
pass

class TwoDataTypesViaInheritanceAndMixin(Second, Correct2, Mixin): # E: No base classes are allowed after "__main__.Correct2" \
class TwoDataTypesViaInheritanceAndMixin(Second, Correct2, Mixin): # E: No non-enum mixin classes are allowed after "__main__.Correct2" \
# E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Correct2"
pass

class MixinAfterEnum1(enum.Enum, Mixin): # E: No base classes are allowed after "enum.Enum"
class MixinAfterEnum1(enum.Enum, Mixin): # E: No non-enum mixin classes are allowed after "enum.Enum"
pass

class MixinAfterEnum2(First, enum.Enum, Mixin): # E: No base classes are allowed after "enum.Enum"
class MixinAfterEnum2(First, enum.Enum, Mixin): # E: No non-enum mixin classes are allowed after "enum.Enum"
pass

class TwoDataTypes(First, Second, enum.Enum): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second"
pass

class TwoDataTypesAndIntEnumMixin(First, Second, enum.IntEnum, Mixin): # E: No base classes are allowed after "enum.IntEnum" \
class TwoDataTypesAndIntEnumMixin(First, Second, enum.IntEnum, Mixin): # E: No non-enum mixin classes are allowed after "enum.IntEnum" \
# E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second"
pass

class ThreeDataTypes(First, Second, Third, enum.Enum): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" \
# E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Third"
pass

class ThreeDataTypesAndMixin(First, Second, Third, enum.Enum, Mixin): # E: No base classes are allowed after "enum.Enum" \
class ThreeDataTypesAndMixin(First, Second, Third, enum.Enum, Mixin): # E: No non-enum mixin classes are allowed after "enum.Enum" \
# E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" \
# E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Third"
pass

class FromEnumAndOther1(Correct2, Second, enum.Enum): # E: No base classes are allowed after "__main__.Correct2" \
class FromEnumAndOther1(Correct2, Second, enum.Enum): # E: No non-enum mixin classes are allowed after "__main__.Correct2" \
# E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second"
pass

class FromEnumAndOther2(Correct2, Second): # E: No base classes are allowed after "__main__.Correct2" \
class FromEnumAndOther2(Correct2, Second): # E: No non-enum mixin classes are allowed after "__main__.Correct2" \
# E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second"
pass
[builtins fixtures/tuple.pyi]
Expand Down