Skip to content

Commit 1c3227d

Browse files
wanda-phiwhitequark
authored andcommitted
lib.enum: use plain EnumMeta as metaclass when shape not used.
1 parent 4e4085a commit 1c3227d

File tree

3 files changed

+25
-12
lines changed

3 files changed

+25
-12
lines changed

amaranth/lib/enum.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,23 @@ def __new__(metacls, name, bases, namespace, shape=None, **kwargs):
8383
category=SyntaxWarning,
8484
stacklevel=2)
8585
# Actually instantiate the enumeration class.
86-
cls = py_enum.EnumMeta.__new__(metacls, name, bases, namespace, **kwargs)
8786
if shape is not None:
87+
cls = py_enum.EnumMeta.__new__(metacls, name, bases, namespace, **kwargs)
8888
# Shape is provided explicitly. Set the `_amaranth_shape_` attribute, and check that
8989
# the values of every member can be cast to the provided shape without truncation.
9090
cls._amaranth_shape_ = shape
9191
else:
9292
# Shape is not provided explicitly. Behave the same as a standard enumeration;
9393
# the lack of `_amaranth_shape_` attribute is used to emit a warning when such
9494
# an enumeration is used in a concatenation.
95-
pass
95+
bases = tuple(
96+
py_enum.Enum if base is Enum else
97+
py_enum.IntEnum if base is IntEnum else
98+
py_enum.Flag if base is Flag else
99+
py_enum.IntFlag if base is IntFlag else base
100+
for base in bases
101+
)
102+
cls = py_enum.EnumMeta.__new__(py_enum.EnumMeta, name, bases, namespace, **kwargs)
96103
return cls
97104

98105
def as_shape(cls):
@@ -144,21 +151,28 @@ def const(cls, init):
144151
return Const(member.value, cls.as_shape())
145152

146153

147-
class Enum(py_enum.Enum, metaclass=EnumMeta):
154+
class Enum(py_enum.Enum):
148155
"""Subclass of the standard :class:`enum.Enum` that has :class:`EnumMeta` as
149156
its metaclass."""
150157

151158

152-
class IntEnum(py_enum.IntEnum, metaclass=EnumMeta):
159+
class IntEnum(py_enum.IntEnum):
153160
"""Subclass of the standard :class:`enum.IntEnum` that has :class:`EnumMeta` as
154161
its metaclass."""
155162

156163

157-
class Flag(py_enum.Flag, metaclass=EnumMeta):
164+
class Flag(py_enum.Flag):
158165
"""Subclass of the standard :class:`enum.Flag` that has :class:`EnumMeta` as
159166
its metaclass."""
160167

161168

162-
class IntFlag(py_enum.IntFlag, metaclass=EnumMeta):
169+
class IntFlag(py_enum.IntFlag):
163170
"""Subclass of the standard :class:`enum.IntFlag` that has :class:`EnumMeta` as
164171
its metaclass."""
172+
173+
# Fix up the metaclass after the fact: the metaclass __new__ requires these classes
174+
# to already be present, and also would not install itself on them due to lack of shape.
175+
Enum.__class__ = EnumMeta
176+
IntEnum.__class__ = EnumMeta
177+
Flag.__class__ = EnumMeta
178+
IntFlag.__class__ = EnumMeta

tests/test_hdl_ast.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ def const(self, init):
10771077
Signal(CastableFromHex(), reset="01")
10781078

10791079
def test_reset_shape_castable_enum_wrong(self):
1080-
class EnumA(AmaranthEnum):
1080+
class EnumA(AmaranthEnum, shape=1):
10811081
X = 1
10821082
with self.assertRaisesRegex(TypeError,
10831083
r"^Reset value must be a constant initializer of <enum 'EnumA'>$"):

tests/test_lib_enum.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import enum as py_enum
22

33
from amaranth import *
4-
from amaranth.lib.enum import Enum
4+
from amaranth.lib.enum import Enum, EnumMeta
55

66
from .utils import *
77

@@ -91,14 +91,13 @@ class EnumA(Enum, shape=unsigned(10)):
9191
A = 1
9292
self.assertRepr(Value.cast(EnumA.A), "(const 10'd1)")
9393

94-
def test_const_no_shape(self):
94+
def test_no_shape(self):
9595
class EnumA(Enum):
9696
Z = 0
9797
A = 10
9898
B = 20
99-
self.assertRepr(EnumA.const(None), "(const 5'd0)")
100-
self.assertRepr(EnumA.const(10), "(const 5'd10)")
101-
self.assertRepr(EnumA.const(EnumA.A), "(const 5'd10)")
99+
self.assertNotIsInstance(EnumA, EnumMeta)
100+
self.assertIsInstance(EnumA, py_enum.EnumMeta)
102101

103102
def test_const_shape(self):
104103
class EnumA(Enum, shape=8):

0 commit comments

Comments
 (0)