Putting a message together

Now let us combine the features we have covered: an author model, a list of tags, and an optional note. You can run this example as a complete script.

from bytespec import ProtoModel, field
from bytespec.types import UInt32

class User(ProtoModel):
    id: UInt32
    name: str

class Message(ProtoModel):
    author: User
    text: str
    tags: list[str] = field(default_factory=list)
    note: str | None = field(flag=0)

message = Message(
    author=User(id=42, name="Anna"),
    text="Hello!",
    tags=["news"],
)
encoded = message.encode()
decoded = Message.decode(encoded)

print(decoded.author.name)  # Anna
print(decoded.text)         # Hello!
print(decoded.tags)         # ['news']
print(decoded.note)         # None

Creation and decoding work just as they did for the first model. Tags are restored as a list, the author as a User, and the omitted note as None. These structures needed no separate serialization calls.

Let us change the note and encode the message again:

decoded.note = "Updated"
updated = Message.decode(decoded.encode())
print(updated.note)  # Updated

Try this example with empty tags and with note="": both values are preserved. Only note=None removes the optional field from the message.

You can now try a model on a single packet from your own protocol. Headers and framing shows how to configure framing bytes; Validating model values explains how to check relationships between fields; Handling errors covers error handling. To read several messages from one buffer, open Files and multiple messages.