From 37795010c3a85ecaba210f764db84078507f593d Mon Sep 17 00:00:00 2001 From: Abdelrahman Elbehery Date: Tue, 21 Feb 2023 22:09:14 +0200 Subject: [PATCH 1/3] [mypyc] fix IntEnum attributes not treated as final values IntEnum test is skipped on python3.8 due to python/cpython#26654 --- mypyc/irbuild/builder.py | 3 +-- mypyc/irbuild/classdef.py | 2 +- mypyc/test-data/run-classes.test | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) 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..46e8bc07bf594 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -630,7 +630,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..31123562cecfc 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -273,6 +273,20 @@ class Pokemon(enum.Enum): assert Pokemon.magikarp.value == 1 assert Pokemon.squirtle.name == 'squirtle' +import sys, enum, typing_extensions + +# skip test on python 3.8 as it does not allow multiple data-type mixins of the same type +if sys.version_info[:2] != (3, 8): + base_cls: typing_extensions.TypeAlias = enum.IntEnum +else: + base_cls: typing_extensions.TypeAlias = enum.Enum + +class Color(base_cls): + GREEN = 1 + +if sys.version_info[:2] != (3, 8): + assert Color.GREEN == 1 + [file other.py] # Force a multi-module test to make sure we can compile multi-file with # non-extension classes From 24edc1440f10d93a5f3db5c48bc3544d60721974 Mon Sep 17 00:00:00 2001 From: Abdelrahman Elbehery Date: Fri, 24 Feb 2023 21:50:23 +0200 Subject: [PATCH 2/3] refactor imports in enum test add reference to bpo associated with skipping test on python 3.8 --- mypyc/test-data/run-classes.test | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index 31123562cecfc..dacc40637366a 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -250,7 +250,9 @@ assert o.get(20) == 20 assert get_class_var() == 'xy' [case testEnum] -from enum import Enum +from enum import Enum, IntEnum, Flag, auto +import sys, typing_extensions + class TestEnum(Enum): _order_ = "a b" @@ -263,9 +265,7 @@ class TestEnum(Enum): assert TestEnum.test() == 3 -import enum - -class Pokemon(enum.Enum): +class Pokemon(Enum): magikarp = 1 squirtle = 2 slowbro = 3 @@ -273,19 +273,17 @@ class Pokemon(enum.Enum): assert Pokemon.magikarp.value == 1 assert Pokemon.squirtle.name == 'squirtle' -import sys, enum, typing_extensions - -# skip test on python 3.8 as it does not allow multiple data-type mixins of the same type +# 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): - base_cls: typing_extensions.TypeAlias = enum.IntEnum + base_cls: typing_extensions.TypeAlias = IntEnum else: - base_cls: typing_extensions.TypeAlias = enum.Enum + base_cls: typing_extensions.TypeAlias = Enum class Color(base_cls): GREEN = 1 if sys.version_info[:2] != (3, 8): - assert Color.GREEN == 1 + assert Color.GREEN.value == 1 [file other.py] # Force a multi-module test to make sure we can compile multi-file with From 87573432fd40058e30421393c1e53707fdc30458 Mon Sep 17 00:00:00 2001 From: Abdelrahman Elbehery Date: Sat, 25 Feb 2023 13:53:29 +0200 Subject: [PATCH 3/3] fix StrEnum build error add tests for StrEnum, Flag and IntFlag --- mypyc/irbuild/classdef.py | 3 +- mypyc/test-data/run-classes.test | 47 ++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index 46e8bc07bf594..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", diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index dacc40637366a..58ef3e805accb 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -250,11 +250,11 @@ assert o.get(20) == 20 assert get_class_var() == 'xy' [case testEnum] -from enum import Enum, IntEnum, Flag, auto +import enum import sys, typing_extensions -class TestEnum(Enum): +class TestEnum(enum.Enum): _order_ = "a b" a : int = 1 b : int = 2 @@ -265,7 +265,7 @@ class TestEnum(Enum): assert TestEnum.test() == 3 -class Pokemon(Enum): +class Pokemon(enum.Enum): magikarp = 1 squirtle = 2 slowbro = 3 @@ -275,22 +275,45 @@ 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): - base_cls: typing_extensions.TypeAlias = IntEnum + int_enum_base_cls: typing_extensions.TypeAlias = enum.IntEnum + int_flag_enum_blase_cls: typing_extensions.TypeAlias = enum.IntFlag else: - base_cls: typing_extensions.TypeAlias = Enum + int_enum_base_cls: typing_extensions.TypeAlias = enum.Enum + int_flag_enum_blase_cls: typing_extensions.TypeAlias = enum.Enum -class Color(base_cls): +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 @@ -299,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