Beautiful, Pythonic protocol buffers that make protocol buffer message classes behave like native Python types
—
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.
Define protocol buffer enums using the proto.Enum base class.
class Enum(enum.IntEnum, metaclass=ProtoEnumMeta):
"""
A enum object that also builds a protobuf enum descriptor.
Inherits from enum.IntEnum, providing integer compatibility while
generating the necessary protocol buffer enum descriptor.
"""
def __hash__(self): ...
def __eq__(self, other): ...
def __ne__(self, other): ...
def __lt__(self, other): ...
def __le__(self, other): ...
def __ge__(self, other): ...
def __gt__(self, other): ...Example usage:
class Status(proto.Enum):
UNKNOWN = 0
ACTIVE = 1
INACTIVE = 2
PENDING = 3
class Priority(proto.Enum):
LOW = 1
MEDIUM = 2
HIGH = 3
CRITICAL = 4
# Use in message definitions
class Task(proto.Message):
title = proto.Field(proto.STRING, number=1)
status = proto.Field(Status, number=2)
priority = proto.Field(Priority, number=3)Proto-plus enums behave like native Python enums with additional integer compatibility.
# Create enum values
status = Status.ACTIVE
priority = Priority.HIGH
# Integer compatibility
print(status == 1) # True
print(priority > 2) # True
print(int(status)) # 1
# String representation
print(status.name) # "ACTIVE"
print(status.value) # 1
print(str(status)) # "Status.ACTIVE"
# Comparison operations
print(Priority.HIGH > Priority.LOW) # True
print(Status.ACTIVE != Status.INACTIVE) # True
# Enum iteration
for status in Status:
print(f"{status.name}: {status.value}")
# Enum lookup
status_by_value = Status(1) # Status.ACTIVE
status_by_name = Status['ACTIVE'] # Status.ACTIVEEnums integrate seamlessly with proto-plus messages.
class OrderStatus(proto.Enum):
DRAFT = 0
SUBMITTED = 1
PROCESSING = 2
SHIPPED = 3
DELIVERED = 4
CANCELLED = 5
class Order(proto.Message):
order_id = proto.Field(proto.STRING, number=1)
status = proto.Field(OrderStatus, number=2)
items = proto.RepeatedField(proto.STRING, number=3)
# Create and manipulate orders
order = Order(
order_id="ORD-001",
status=OrderStatus.DRAFT,
items=["item1", "item2"]
)
# Update status
order.status = OrderStatus.SUBMITTED
# Check status
if order.status == OrderStatus.PROCESSING:
print("Order is being processed")
# Conditional logic
if order.status >= OrderStatus.SHIPPED:
print("Order has shipped")Enums serialize appropriately in JSON and dictionary formats.
class Color(proto.Enum):
RED = 1
GREEN = 2
BLUE = 3
class Product(proto.Message):
name = proto.Field(proto.STRING, number=1)
color = proto.Field(Color, number=2)
product = Product(name="Widget", color=Color.RED)
# JSON serialization with enum as integer (default)
json_str = Product.to_json(product)
# {"name": "Widget", "color": 1}
# JSON serialization with enum as string
json_str = Product.to_json(product, use_integers_for_enums=False)
# {"name": "Widget", "color": "RED"}
# Dictionary conversion
product_dict = Product.to_dict(product)
# {"name": "Widget", "color": 1}
# Create from dictionary with integer
product2 = Product({"name": "Gadget", "color": 2}) # color=Color.GREEN
# Create from dictionary with enum instance
product3 = Product({"name": "Tool", "color": Color.BLUE})Enums work seamlessly with repeated fields and collections.
class Permission(proto.Enum):
READ = 1
WRITE = 2
EXECUTE = 4
ADMIN = 8
class User(proto.Message):
username = proto.Field(proto.STRING, number=1)
permissions = proto.RepeatedField(Permission, number=2)
# Create user with multiple permissions
user = User(
username="alice",
permissions=[Permission.READ, Permission.WRITE]
)
# Add permissions
user.permissions.append(Permission.EXECUTE)
# Check permissions
if Permission.ADMIN in user.permissions:
print("User has admin access")
# Iterate permissions
for perm in user.permissions:
print(f"Permission: {perm.name}")Enums can be used as both keys and values in map fields.
class Region(proto.Enum):
US_EAST = 1
US_WEST = 2
EUROPE = 3
ASIA = 4
class ServiceLevel(proto.Enum):
BASIC = 1
STANDARD = 2
PREMIUM = 3
class Configuration(proto.Message):
# Enum as map key
region_settings = proto.MapField(Region, proto.STRING, number=1)
# Enum as map value
service_levels = proto.MapField(proto.STRING, ServiceLevel, number=2)
config = Configuration(
region_settings={
Region.US_EAST: "config-east.json",
Region.EUROPE: "config-eu.json"
},
service_levels={
"web": ServiceLevel.STANDARD,
"api": ServiceLevel.PREMIUM
}
)Proto-plus enums provide validation and clear error messages.
class Color(proto.Enum):
RED = 1
GREEN = 2
BLUE = 3
# Valid enum creation
color = Color.RED
# Invalid enum value raises ValueError
try:
invalid_color = Color(99)
except ValueError as e:
print(f"Invalid enum value: {e}")
# Invalid enum name raises KeyError
try:
invalid_color = Color['PURPLE']
except KeyError as e:
print(f"Invalid enum name: {e}")
# Message field validation
class Item(proto.Message):
color = proto.Field(Color, number=1)
# Valid assignment
item = Item(color=Color.RED)
item.color = Color.BLUE
# Invalid assignment raises error
try:
item.color = 99 # Invalid enum value
except ValueError as e:
print(f"Field validation error: {e}")Customize enum behavior with protocol buffer options.
class Status(proto.Enum):
_pb_options = {"allow_alias": True}
UNKNOWN = 0
ACTIVE = 1
ENABLED = 1 # Alias for ACTIVE
INACTIVE = 2Protocol buffer enums should have zero values for proper defaults.
# Recommended: Include zero value
class Status(proto.Enum):
UNSPECIFIED = 0 # Zero value
ACTIVE = 1
INACTIVE = 2
# Usage in messages gets proper defaults
class User(proto.Message):
name = proto.Field(proto.STRING, number=1)
status = proto.Field(Status, number=2) # Defaults to Status.UNSPECIFIED
user = User(name="alice")
print(user.status) # Status.UNSPECIFIEDInstall with Tessl CLI
npx tessl i tessl/pypi-proto-plus