Skip to content

How to store text and bytes

Text and bytes vary in length, but every field of a box has a fixed size. So when you declare a str or bytes field, you also say how much room it gets, its capacity: the most bytes it can hold. This guide shows how to choose it and what happens when a value doesn't fit.

1. Declare the field with a capacity

Wrap the type in Annotated and add a Capacity:

from typing import Annotated

from sharedbox import Capacity, SharedBox


class Camera(SharedBox, name="example-camera"):
    label: Annotated[str, Capacity(16)] = ""
    frame: Annotated[bytes, Capacity(1024)] = b""

2. Write and read values

From then on you use the field like any other attribute:

camera = Camera()
camera.label = "front"
camera.frame = bytes(range(8))
print(camera.label, len(camera.frame))  # front 8

You can also assign a bytearray or a memoryview to a bytes field; reading it back always gives you bytes.

3. Handle a value that is too long

If you assign a value longer than the capacity, you get a ValueError and the field keeps its old value, so a reader never sees half of it:

try:
    camera.label = "front camera, left side"
except ValueError as error:
    print(error)  # Camera.label holds at most 16 bytes; the value encodes to 23
print(camera.label)  # front

4. Count bytes, not characters

The capacity counts bytes of the UTF-8 encoding, not characters, and a character takes between 1 and 4 bytes. Text with accents or other scripts fills the room faster than it looks:

print(len("été"), len("été".encode()))  # 3 5

To be sure n characters of any language fit, give the field a capacity of 4 * n. If you know the text is plain ASCII, n is enough.

5. Cut a value to fit

Sometimes you'd rather keep the start of a long text than refuse it. Cut its encoding to the capacity, and drop any character the cut split in two, as this helper does:

def fit(text: str, size: int) -> str:
    return text.encode()[:size].decode(errors="ignore")


camera.label = fit("front camera, left side", 16)
print(camera.label)  # front camera, le
The whole script
"""The script of the guide "How to store text and bytes"."""

from typing import Annotated

from sharedbox import Capacity, SharedBox


class Camera(SharedBox, name="example-camera"):
    label: Annotated[str, Capacity(16)] = ""
    frame: Annotated[bytes, Capacity(1024)] = b""



camera = Camera()
camera.label = "front"
camera.frame = bytes(range(8))
print(camera.label, len(camera.frame))  # front 8

try:
    camera.label = "front camera, left side"
except ValueError as error:
    print(error)  # Camera.label holds at most 16 bytes; the value encodes to 23
print(camera.label)  # front

print(len("été"), len("été".encode()))  # 3 5


def fit(text: str, size: int) -> str:
    return text.encode()[:size].decode(errors="ignore")


camera.label = fit("front camera, left side", 16)
print(camera.label)  # front camera, le

camera.close()
Camera.unlink()