0
# Enum System
1
2
The Enum system provides protocol buffer enums that behave like native Python enums while maintaining full compatibility with protocol buffer serialization and integer operations. Proto-plus enums extend Python's IntEnum to provide seamless integration with both Python code and protocol buffer wire format.
3
4
## Capabilities
5
6
### Enum Definition
7
8
Define protocol buffer enums using the proto.Enum base class.
9
10
```python { .api }
11
class Enum(enum.IntEnum, metaclass=ProtoEnumMeta):
12
"""
13
A enum object that also builds a protobuf enum descriptor.
14
15
Inherits from enum.IntEnum, providing integer compatibility while
16
generating the necessary protocol buffer enum descriptor.
17
"""
18
19
def __hash__(self): ...
20
def __eq__(self, other): ...
21
def __ne__(self, other): ...
22
def __lt__(self, other): ...
23
def __le__(self, other): ...
24
def __ge__(self, other): ...
25
def __gt__(self, other): ...
26
```
27
28
Example usage:
29
30
```python
31
class Status(proto.Enum):
32
UNKNOWN = 0
33
ACTIVE = 1
34
INACTIVE = 2
35
PENDING = 3
36
37
class Priority(proto.Enum):
38
LOW = 1
39
MEDIUM = 2
40
HIGH = 3
41
CRITICAL = 4
42
43
# Use in message definitions
44
class Task(proto.Message):
45
title = proto.Field(proto.STRING, number=1)
46
status = proto.Field(Status, number=2)
47
priority = proto.Field(Priority, number=3)
48
```
49
50
### Enum Usage and Behavior
51
52
Proto-plus enums behave like native Python enums with additional integer compatibility.
53
54
```python
55
# Create enum values
56
status = Status.ACTIVE
57
priority = Priority.HIGH
58
59
# Integer compatibility
60
print(status == 1) # True
61
print(priority > 2) # True
62
print(int(status)) # 1
63
64
# String representation
65
print(status.name) # "ACTIVE"
66
print(status.value) # 1
67
print(str(status)) # "Status.ACTIVE"
68
69
# Comparison operations
70
print(Priority.HIGH > Priority.LOW) # True
71
print(Status.ACTIVE != Status.INACTIVE) # True
72
73
# Enum iteration
74
for status in Status:
75
print(f"{status.name}: {status.value}")
76
77
# Enum lookup
78
status_by_value = Status(1) # Status.ACTIVE
79
status_by_name = Status['ACTIVE'] # Status.ACTIVE
80
```
81
82
### Message Integration
83
84
Enums integrate seamlessly with proto-plus messages.
85
86
```python
87
class OrderStatus(proto.Enum):
88
DRAFT = 0
89
SUBMITTED = 1
90
PROCESSING = 2
91
SHIPPED = 3
92
DELIVERED = 4
93
CANCELLED = 5
94
95
class Order(proto.Message):
96
order_id = proto.Field(proto.STRING, number=1)
97
status = proto.Field(OrderStatus, number=2)
98
items = proto.RepeatedField(proto.STRING, number=3)
99
100
# Create and manipulate orders
101
order = Order(
102
order_id="ORD-001",
103
status=OrderStatus.DRAFT,
104
items=["item1", "item2"]
105
)
106
107
# Update status
108
order.status = OrderStatus.SUBMITTED
109
110
# Check status
111
if order.status == OrderStatus.PROCESSING:
112
print("Order is being processed")
113
114
# Conditional logic
115
if order.status >= OrderStatus.SHIPPED:
116
print("Order has shipped")
117
```
118
119
### JSON and Dictionary Serialization
120
121
Enums serialize appropriately in JSON and dictionary formats.
122
123
```python
124
class Color(proto.Enum):
125
RED = 1
126
GREEN = 2
127
BLUE = 3
128
129
class Product(proto.Message):
130
name = proto.Field(proto.STRING, number=1)
131
color = proto.Field(Color, number=2)
132
133
product = Product(name="Widget", color=Color.RED)
134
135
# JSON serialization with enum as integer (default)
136
json_str = Product.to_json(product)
137
# {"name": "Widget", "color": 1}
138
139
# JSON serialization with enum as string
140
json_str = Product.to_json(product, use_integers_for_enums=False)
141
# {"name": "Widget", "color": "RED"}
142
143
# Dictionary conversion
144
product_dict = Product.to_dict(product)
145
# {"name": "Widget", "color": 1}
146
147
# Create from dictionary with integer
148
product2 = Product({"name": "Gadget", "color": 2}) # color=Color.GREEN
149
150
# Create from dictionary with enum instance
151
product3 = Product({"name": "Tool", "color": Color.BLUE})
152
```
153
154
### Repeated Enum Fields
155
156
Enums work seamlessly with repeated fields and collections.
157
158
```python
159
class Permission(proto.Enum):
160
READ = 1
161
WRITE = 2
162
EXECUTE = 4
163
ADMIN = 8
164
165
class User(proto.Message):
166
username = proto.Field(proto.STRING, number=1)
167
permissions = proto.RepeatedField(Permission, number=2)
168
169
# Create user with multiple permissions
170
user = User(
171
username="alice",
172
permissions=[Permission.READ, Permission.WRITE]
173
)
174
175
# Add permissions
176
user.permissions.append(Permission.EXECUTE)
177
178
# Check permissions
179
if Permission.ADMIN in user.permissions:
180
print("User has admin access")
181
182
# Iterate permissions
183
for perm in user.permissions:
184
print(f"Permission: {perm.name}")
185
```
186
187
### Map Fields with Enums
188
189
Enums can be used as both keys and values in map fields.
190
191
```python
192
class Region(proto.Enum):
193
US_EAST = 1
194
US_WEST = 2
195
EUROPE = 3
196
ASIA = 4
197
198
class ServiceLevel(proto.Enum):
199
BASIC = 1
200
STANDARD = 2
201
PREMIUM = 3
202
203
class Configuration(proto.Message):
204
# Enum as map key
205
region_settings = proto.MapField(Region, proto.STRING, number=1)
206
207
# Enum as map value
208
service_levels = proto.MapField(proto.STRING, ServiceLevel, number=2)
209
210
config = Configuration(
211
region_settings={
212
Region.US_EAST: "config-east.json",
213
Region.EUROPE: "config-eu.json"
214
},
215
service_levels={
216
"web": ServiceLevel.STANDARD,
217
"api": ServiceLevel.PREMIUM
218
}
219
)
220
```
221
222
### Enum Validation and Error Handling
223
224
Proto-plus enums provide validation and clear error messages.
225
226
```python
227
class Color(proto.Enum):
228
RED = 1
229
GREEN = 2
230
BLUE = 3
231
232
# Valid enum creation
233
color = Color.RED
234
235
# Invalid enum value raises ValueError
236
try:
237
invalid_color = Color(99)
238
except ValueError as e:
239
print(f"Invalid enum value: {e}")
240
241
# Invalid enum name raises KeyError
242
try:
243
invalid_color = Color['PURPLE']
244
except KeyError as e:
245
print(f"Invalid enum name: {e}")
246
247
# Message field validation
248
class Item(proto.Message):
249
color = proto.Field(Color, number=1)
250
251
# Valid assignment
252
item = Item(color=Color.RED)
253
item.color = Color.BLUE
254
255
# Invalid assignment raises error
256
try:
257
item.color = 99 # Invalid enum value
258
except ValueError as e:
259
print(f"Field validation error: {e}")
260
```
261
262
## Enum Protocol Buffer Features
263
264
### Enum Options
265
266
Customize enum behavior with protocol buffer options.
267
268
```python
269
class Status(proto.Enum):
270
_pb_options = {"allow_alias": True}
271
272
UNKNOWN = 0
273
ACTIVE = 1
274
ENABLED = 1 # Alias for ACTIVE
275
INACTIVE = 2
276
```
277
278
### Zero Values
279
280
Protocol buffer enums should have zero values for proper defaults.
281
282
```python
283
# Recommended: Include zero value
284
class Status(proto.Enum):
285
UNSPECIFIED = 0 # Zero value
286
ACTIVE = 1
287
INACTIVE = 2
288
289
# Usage in messages gets proper defaults
290
class User(proto.Message):
291
name = proto.Field(proto.STRING, number=1)
292
status = proto.Field(Status, number=2) # Defaults to Status.UNSPECIFIED
293
294
user = User(name="alice")
295
print(user.status) # Status.UNSPECIFIED
296
```