diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index f37fae608083b..41aa428f9a9a6 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -973,8 +973,7 @@ def get_final_ref(self, expr: MemberExpr) -> tuple[str, Var, bool] | None: sym = expr.expr.node.get(expr.name) if sym and isinstance(sym.node, Var): # Enum attribute are treated as final since they are added to the global cache - expr_fullname = expr.expr.node.bases[0].type.fullname - is_final = sym.node.is_final or expr_fullname == "enum.Enum" + is_final = sym.node.is_final or expr.expr.node.is_enum if is_final: final_var = sym.node fullname = f"{sym.node.info.fullname}.{final_var.name}" diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index 59b1c05a0ddbd..c5d1920298495 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -467,12 +467,13 @@ def populate_non_ext_bases(builder: IRBuilder, cdef: ClassDef) -> Value: The tuple is passed to the metaclass constructor. """ is_named_tuple = cdef.info.is_named_tuple + is_enum = cdef.info.is_enum ir = builder.mapper.type_to_ir[cdef.info] bases = [] for cls in cdef.info.mro[1:]: if cls.fullname == "builtins.object": continue - if is_named_tuple and cls.fullname in ( + if (is_named_tuple or is_enum) and cls.fullname in ( "typing.Sequence", "typing.Iterable", "typing.Collection", @@ -630,7 +631,7 @@ def add_non_ext_class_attr( # are final. if ( cdef.info.bases - and cdef.info.bases[0].type.fullname == "enum.Enum" + and cdef.info.bases[0].type.is_enum # Skip these since Enum will remove it and lvalue.name not in ENUM_REMOVED_PROPS ): diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index 92ec3873bf382..58ef3e805accb 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -250,9 +250,11 @@ assert o.get(20) == 20 assert get_class_var() == 'xy' [case testEnum] -from enum import Enum +import enum +import sys, typing_extensions + -class TestEnum(Enum): +class TestEnum(enum.Enum): _order_ = "a b" a : int = 1 b : int = 2 @@ -263,8 +265,6 @@ class TestEnum(Enum): assert TestEnum.test() == 3 -import enum - class Pokemon(enum.Enum): magikarp = 1 squirtle = 2 @@ -273,12 +273,47 @@ class Pokemon(enum.Enum): assert Pokemon.magikarp.value == 1 assert Pokemon.squirtle.name == 'squirtle' +# skip test on python 3.8 as it does not allow multiple data-type mixins of the same type (see bpo-39587) +if sys.version_info[:2] != (3, 8): + int_enum_base_cls: typing_extensions.TypeAlias = enum.IntEnum + int_flag_enum_blase_cls: typing_extensions.TypeAlias = enum.IntFlag +else: + int_enum_base_cls: typing_extensions.TypeAlias = enum.Enum + int_flag_enum_blase_cls: typing_extensions.TypeAlias = enum.Enum + +class Color(int_enum_base_cls): + GREEN = 1 + +if sys.version_info[:2] != (3, 8): + assert Color.GREEN.value == 1 + +if sys.version_info[0] >= 3 and sys.version_info[1] >= 11: + str_enum_base_cls: typing_extensions.TypeAlias = enum.StrEnum +else: + str_enum_base_cls: typing_extensions.TypeAlias = enum.Enum + +class BuildEnum(str_enum_base_cls): + DEBUG = "debug" + RELEASE = "release" + +class ColorFlagEnum(enum.Flag): + RED = enum.auto() + GREEN = enum.auto() + BLUE = enum.auto() + +class ColorIntFlagEnum(int_flag_enum_blase_cls): + RED = enum.auto() + GREEN = enum.auto() + BLUE = enum.auto() + + [file other.py] # Force a multi-module test to make sure we can compile multi-file with # non-extension classes [file driver.py] import sys +from native import ColorFlagEnum # "_order_" isn't supported in 3.5 if sys.version_info[:2] > (3, 5): from native import TestEnum @@ -287,6 +322,18 @@ if sys.version_info[:2] > (3, 5): assert TestEnum.b.name == 'b' assert TestEnum.b.value == 2 +# StrEnum is available in 3.11 +if sys.version_info[:2] >= (3, 11): + from native import BuildEnum + assert BuildEnum.DEBUG == "debug" + +purple = ColorFlagEnum.RED | ColorFlagEnum.BLUE +assert ColorFlagEnum.RED in purple + +if sys.version_info[:2] != (3, 8): + from native import ColorIntFlagEnum + assert ColorIntFlagEnum.GREEN == ColorIntFlagEnum.RED + 1 + [case testGetAttribute] class C: x: int