protobuf notes

repeated

See

  • <https://protobuf.dev/reference/python/python-generated/#repeated-fields>

Two examples below:

    1. the repeated field contains messages

    1. the repeated field contain primitive fields

message NodeProto {
  repeated string input = 1;    // namespace Value
}

message TensorShapeProto {
  message Dimension {
    oneof value {
      int64 dim_value = 1;
      string dim_param = 2;   // namespace Shape
    };
    // Standard denotation can optionally be used to denote tensor
    // dimensions with standard semantic descriptions to ensure
    // that operations are applied to the correct axis of a tensor.
    // Refer to https://github.com/onnx/onnx/blob/main/docs/DimensionDenotation.md#denotation-definition
    // for pre-defined dimension denotations.
    optional string denotation = 3;
  };
  repeated Dimension dim = 1;
}

Usage in Python:

#!/usr/bin/env python3

import onnx

# Works as a python list, but it is not a Python list


def test1():
    n = onnx.NodeProto()
    assert len(n.input) == 0, len(n.input)
    n.input.append("i0")
    n.input.append("i1")

    n.input.extend(["i2", "i3"])
    print(n)
    """
    input: "i0"
    input: "i1"
    input: "i2"
    input: "i3"
    """

    assert len(n.input) == 4
    assert n.input[0] == "i0"
    assert n.input[1] == "i1"
    assert n.input[2] == "i2"
    assert n.input[3] == "i3"

    del n.input[0]
    assert len(n.input) == 3
    assert n.input == ["i1", "i2", "i3"], n.input

    # There are at least 3 methods to clear a repeated fields

    # Method 1: Use ClearField()

    n.ClearField("input")
    assert len(n.input) == 0

    # Method 2: Use del
    n.input.append("ii")
    assert len(n.input) == 1
    del n.input[:]

    assert len(n.input) == 0

    # Method 3, use pop
    n.input.append("1")
    n.input.append("2")
    n.input.extend(["3", "4", "5"])

    while len(n.input) > 0:
        n.input.pop()

    assert len(n.input) == 0

    # Method 4
    n.input.append("10")
    assert len(n.input) == 1
    n.input[:] = []
    assert len(n.input) == 0


def test2():
    s = onnx.TensorShapeProto()
    assert len(s.dim) == 0, len(s.dim)

    d = s.dim.add()
    assert id(d) == id(s.dim[0]), (id(d), id(s.dim[0]))

    d.dim_value = 1

    p = s.dim.add()
    p.dim_param = "N"

    # Copy an existing one
    k = onnx.TensorShapeProto.Dimension()
    k.dim_value = 10

    s.dim.append(k)
    assert s.dim[2] == k, (s.dim[2], k)

    # It is a copy, so id is different
    assert id(s.dim[2]) != id(k), (id(s.dim[2]), id(k))

    print(s)
    """
    dim {
      dim_value: 1
    }
    dim {
      dim_param: "N"
    }
    dim {
      dim_value: 10
    }
    """


def main():
    test1()
    test2()


if __name__ == "__main__":
    main()