Bases: Data[frozenset[EnumType]], Generic[EnumType]
Core helper for BitEnumAttributes. Takes a StrEnum type parameter, and
defines parsing/printing automatically from its values.
Additionally, two values can be given to designate all/none bits being set.
example:
```python
class MyBitEnum(StrEnum):
First = auto()
Second = auto()
class MyBitEnumAttribute(BitEnumAttribute[MyBitEnum]):
name = "example.my_bit_enum"
none_value = "none"
all_value = "all"
Source code in xdsl/dialects/utils/bit_enum_attribute.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 | @dataclass(frozen=True, init=False)
class BitEnumAttribute(Data[frozenset[EnumType]], Generic[EnumType]):
"""
Core helper for BitEnumAttributes. Takes a StrEnum type parameter, and
defines parsing/printing automatically from its values.
Additionally, two values can be given to designate all/none bits being set.
example:
```python
class MyBitEnum(StrEnum):
First = auto()
Second = auto()
class MyBitEnumAttribute(BitEnumAttribute[MyBitEnum]):
name = "example.my_bit_enum"
none_value = "none"
all_value = "all"
"""
enum_type: ClassVar[type[StrEnum]]
none_value: ClassVar[str | None] = None
all_value: ClassVar[str | None] = None
separator_value: ClassVar[str] = ","
delimiter_value: ClassVar[Parser.Delimiter] = Parser.Delimiter.ANGLE
def __init__(self, flags: None | Iterable[EnumType] | str) -> None:
flags_: frozenset[EnumType]
match flags:
case self.none_value | None:
flags_ = frozenset()
case self.all_value:
flags_ = cast(frozenset[EnumType], frozenset(self.enum_type))
case other if isinstance(other, str):
raise TypeError(
f"expected string parameter to be one of {self.none_value} or {self.all_value}, got {other}"
)
case other:
assert not isinstance(other, str)
flags_ = frozenset(other)
super().__init__(flags_)
def __init_subclass__(cls) -> None:
"""
Extract and store the Enum type used by the subclass for use in
parsing/printing.
Subclass implementations are also constrained to keep implementations
reasonable, unless more complex use cases appear.
The constraint(s) are:
- Only direct, specialized inheritance is allowed. That is, using a
subclass of BitEnumAttribute as a base class is *not supported*.
This simplifies type-hacking code and I don't see it being too
restrictive anytime soon.
"""
super().__init_subclass__()
orig_bases = getattr(cls, "__orig_bases__")
enumattr = next(b for b in orig_bases if get_origin(b) is BitEnumAttribute)
enum_type = get_args(enumattr)[0]
if isinstance(enum_type, TypeVar):
raise TypeError("Only direct inheritance from BitEnumAttribute is allowed.")
cls.enum_type = enum_type
@property
@deprecated("Please use .data instead")
def flags(self) -> set[EnumType]:
return set(self.data)
@classmethod
def parse_parameter(cls, parser: AttrParser) -> frozenset[EnumType]:
def parse_element() -> set[EnumType]:
if (
cls.none_value is not None
and parser.parse_optional_keyword(cls.none_value) is not None
):
return set()
if (
cls.all_value is not None
and parser.parse_optional_keyword(cls.all_value) is not None
):
return set(cast(Iterable[EnumType], cls.enum_type))
value = parser.parse_str_enum(cls.enum_type)
return {cast(type[EnumType], cls.enum_type)(value)}
flag_sets = parser.parse_list(
cls.delimiter_value, parse_element, cls.separator_value
)
if not flag_sets:
return frozenset()
res: set[EnumType] = set()
for flag_set in flag_sets:
res |= flag_set
return frozenset(res)
def print_parameter(self, printer: Printer):
match self.delimiter_value:
case Parser.Delimiter.NONE:
delimiter = nullcontext()
case _:
delimiter = printer.delimited(*self.delimiter_value.value)
with delimiter:
flags = self.data
if not flags and self.none_value is not None:
printer.print_string(self.none_value)
elif len(flags) == len(self.enum_type) and self.all_value is not None:
printer.print_string(self.all_value)
else:
# make sure we emit flags in a consistent order
printer.print_list(
tuple(flag.value for flag in self.enum_type if flag in flags),
printer.print_string,
self.separator_value,
)
|
enum_type: type[StrEnum]
class-attribute
none_value: str | None = None
class-attribute
all_value: str | None = None
class-attribute
separator_value: str = ','
class-attribute
delimiter_value: Parser.Delimiter = Parser.Delimiter.ANGLE
class-attribute
flags: set[EnumType]
property
__init__(flags: None | Iterable[EnumType] | str) -> None
Source code in xdsl/dialects/utils/bit_enum_attribute.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 | def __init__(self, flags: None | Iterable[EnumType] | str) -> None:
flags_: frozenset[EnumType]
match flags:
case self.none_value | None:
flags_ = frozenset()
case self.all_value:
flags_ = cast(frozenset[EnumType], frozenset(self.enum_type))
case other if isinstance(other, str):
raise TypeError(
f"expected string parameter to be one of {self.none_value} or {self.all_value}, got {other}"
)
case other:
assert not isinstance(other, str)
flags_ = frozenset(other)
super().__init__(flags_)
|
__init_subclass__() -> None
Extract and store the Enum type used by the subclass for use in
parsing/printing.
Subclass implementations are also constrained to keep implementations
reasonable, unless more complex use cases appear.
The constraint(s) are:
- Only direct, specialized inheritance is allowed. That is, using a
subclass of BitEnumAttribute as a base class is not supported.
This simplifies type-hacking code and I don't see it being too
restrictive anytime soon.
Source code in xdsl/dialects/utils/bit_enum_attribute.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 | def __init_subclass__(cls) -> None:
"""
Extract and store the Enum type used by the subclass for use in
parsing/printing.
Subclass implementations are also constrained to keep implementations
reasonable, unless more complex use cases appear.
The constraint(s) are:
- Only direct, specialized inheritance is allowed. That is, using a
subclass of BitEnumAttribute as a base class is *not supported*.
This simplifies type-hacking code and I don't see it being too
restrictive anytime soon.
"""
super().__init_subclass__()
orig_bases = getattr(cls, "__orig_bases__")
enumattr = next(b for b in orig_bases if get_origin(b) is BitEnumAttribute)
enum_type = get_args(enumattr)[0]
if isinstance(enum_type, TypeVar):
raise TypeError("Only direct inheritance from BitEnumAttribute is allowed.")
cls.enum_type = enum_type
|
parse_parameter(parser: AttrParser) -> frozenset[EnumType]
classmethod
Source code in xdsl/dialects/utils/bit_enum_attribute.py
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 | @classmethod
def parse_parameter(cls, parser: AttrParser) -> frozenset[EnumType]:
def parse_element() -> set[EnumType]:
if (
cls.none_value is not None
and parser.parse_optional_keyword(cls.none_value) is not None
):
return set()
if (
cls.all_value is not None
and parser.parse_optional_keyword(cls.all_value) is not None
):
return set(cast(Iterable[EnumType], cls.enum_type))
value = parser.parse_str_enum(cls.enum_type)
return {cast(type[EnumType], cls.enum_type)(value)}
flag_sets = parser.parse_list(
cls.delimiter_value, parse_element, cls.separator_value
)
if not flag_sets:
return frozenset()
res: set[EnumType] = set()
for flag_set in flag_sets:
res |= flag_set
return frozenset(res)
|
print_parameter(printer: Printer)
Source code in xdsl/dialects/utils/bit_enum_attribute.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 | def print_parameter(self, printer: Printer):
match self.delimiter_value:
case Parser.Delimiter.NONE:
delimiter = nullcontext()
case _:
delimiter = printer.delimited(*self.delimiter_value.value)
with delimiter:
flags = self.data
if not flags and self.none_value is not None:
printer.print_string(self.none_value)
elif len(flags) == len(self.enum_type) and self.all_value is not None:
printer.print_string(self.all_value)
else:
# make sure we emit flags in a consistent order
printer.print_list(
tuple(flag.value for flag in self.enum_type if flag in flags),
printer.print_string,
self.separator_value,
)
|