Beautiful, Pythonic protocol buffers that make protocol buffer message classes behave like native Python types
—
The Message system provides the core functionality for defining protocol buffer messages that behave like native Python classes. Messages automatically handle serialization, deserialization, type conversion, and provide a Pythonic interface for working with structured data.
Define protocol buffer messages as Python classes using the Message base class. The metaclass automatically generates protocol buffer descriptors and provides seamless integration.
class Message(metaclass=MessageMeta):
"""
Abstract base class for protocol buffer messages.
Args:
mapping (Union[dict, Message]): A dictionary or message to be used to
determine the values for this message.
ignore_unknown_fields (Optional[bool]): If True, do not raise errors for
unknown fields. Only applied if mapping is a mapping type or there
are keyword parameters.
kwargs (dict): Keys and values corresponding to the fields of the message.
"""
def __init__(self, mapping=None, *, ignore_unknown_fields=False, **kwargs): ...Example usage:
class Address(proto.Message):
street = proto.Field(proto.STRING, number=1)
city = proto.Field(proto.STRING, number=2)
zip_code = proto.Field(proto.STRING, number=3)
class Person(proto.Message):
name = proto.Field(proto.STRING, number=1)
age = proto.Field(proto.INT32, number=2)
address = proto.Field(Address, number=3)
# Create message instances
person = Person(
name="John Doe",
age=25,
address={"street": "123 Main St", "city": "Anytown", "zip_code": "12345"}
)
# Or using keyword arguments
person = Person(name="Jane Doe", age=30)Access the underlying protocol buffer objects and perform low-level operations when needed.
@classmethod
def pb(cls, obj=None, *, coerce: bool = False):
"""
Return the underlying protobuf Message class or instance.
Args:
obj: If provided, and an instance of cls, return the underlying
protobuf instance.
coerce (bool): If provided, will attempt to coerce obj to cls
if it is not already an instance.
Returns:
The protobuf class (if obj is None) or protobuf instance
"""
@classmethod
def wrap(cls, pb):
"""
Return a Message object that shallowly wraps the descriptor.
Args:
pb: A protocol buffer object, such as would be returned by pb().
Returns:
Message instance wrapping the protobuf object
"""Example usage:
# Get the underlying protobuf class
pb_class = Person.pb()
# Get the underlying protobuf instance
pb_instance = Person.pb(person)
# Wrap an existing protobuf object
wrapped = Person.wrap(pb_instance)Convert messages to and from binary format for storage and transmission.
@classmethod
def serialize(cls, instance) -> bytes:
"""
Return the serialized proto.
Args:
instance: An instance of this message type, or something compatible
(accepted by the type's constructor).
Returns:
bytes: The serialized representation of the protocol buffer.
"""
@classmethod
def deserialize(cls, payload: bytes) -> "Message":
"""
Given a serialized proto, deserialize it into a Message instance.
Args:
payload (bytes): The serialized proto.
Returns:
Message: An instance of the message class against which this
method was called.
"""Example usage:
# Serialize to bytes
data = Person.serialize(person)
# Deserialize from bytes
person_copy = Person.deserialize(data)Convert messages to and from JSON format with extensive customization options.
@classmethod
def to_json(cls, instance, *, use_integers_for_enums=True,
including_default_value_fields=None, preserving_proto_field_name=False,
sort_keys=False, indent=2, float_precision=None,
always_print_fields_with_no_presence=None) -> str:
"""
Given a message instance, serialize it to json.
Args:
instance: An instance of this message type, or something compatible.
use_integers_for_enums (Optional[bool]): Whether enum values should be
represented by strings (False) or integers (True). Default is True.
including_default_value_fields (Optional[bool]): If True, include fields
that are set to their default values in the output.
preserving_proto_field_name (Optional[bool]): Whether field name
representations preserve proto case (snake_case) or use lowerCamelCase.
sort_keys (Optional[bool]): If True, then the output will be sorted by field names.
indent (Optional[int]): The JSON object will be pretty-printed with this indent level.
float_precision (Optional[int]): If set, use this to specify float field valid digits.
always_print_fields_with_no_presence (Optional[bool]): If True, fields without
presence will always be serialized.
Returns:
str: The json string representation of the protocol buffer.
"""
@classmethod
def from_json(cls, payload, *, ignore_unknown_fields=False) -> "Message":
"""
Given a json string representing an instance, parse it into a message.
Args:
payload: A json string representing a message.
ignore_unknown_fields (Optional[bool]): If True, do not raise errors
for unknown fields.
Returns:
Message: An instance of the message class against which this method was called.
"""Example usage:
# Convert to JSON
json_str = Person.to_json(person, indent=4, sort_keys=True)
# Parse from JSON
person_from_json = Person.from_json(json_str)Convert messages to and from Python dictionaries for easy integration with Python data structures.
@classmethod
def to_dict(cls, instance, *, use_integers_for_enums=True,
preserving_proto_field_name=True, including_default_value_fields=None,
float_precision=None, always_print_fields_with_no_presence=None) -> dict:
"""
Given a message instance, return its representation as a python dict.
Args:
instance: An instance of this message type, or something compatible.
use_integers_for_enums (Optional[bool]): Whether enum values should be
represented by strings (False) or integers (True). Default is True.
preserving_proto_field_name (Optional[bool]): Whether field name
representations preserve proto case (snake_case) or use lowerCamelCase.
including_default_value_fields (Optional[bool]): If True, include fields
that are set to their default values in the output.
float_precision (Optional[int]): If set, use this to specify float field valid digits.
always_print_fields_with_no_presence (Optional[bool]): If True, fields without
presence will always be serialized.
Returns:
dict: A representation of the protocol buffer using pythonic data structures.
"""Example usage:
# Convert to dictionary
person_dict = Person.to_dict(person)
# Create from dictionary
person_from_dict = Person(person_dict)Copy data from other messages or dictionaries into existing message instances.
@classmethod
def copy_from(cls, instance, other):
"""
Equivalent for protobuf.Message.CopyFrom.
Args:
instance: An instance of this message type
other (Union[dict, Message]): A dictionary or message to reinitialize
the values for this message.
"""Example usage:
person1 = Person(name="Alice", age=25)
person2 = Person()
# Copy data from another message
Person.copy_from(person2, person1)
# Copy data from a dictionary
Person.copy_from(person2, {"name": "Bob", "age": 30})Messages behave like native Python objects with standard Python protocols:
person.name, person.age'name' in person checks if field was setbool(person) returns True if any field is setperson1 == person2 compares message contentsstr(person) and repr(person) show message contentsperson.name = "New Name"del person.name clears the fieldInstall with Tessl CLI
npx tessl i tessl/pypi-proto-plus