Protobuf and Python: How to add messages to "repeatable Any" field?

10.8k Views Asked by At

I have a proto message:

syntax = "proto3";

import "google/protobuf/any.proto";

message Task {
    repeated google.protobuf.Any targets = 1;
    // ...
}

message Target {
    string name = 1;
    // ...
}

How should I add Target messages into Task.targets?

In official docs I've found info about how to assign value to a single Any type value, however in my case I have repeated Any field type.

Edit: Task.targets may contain different types of targets, that's why Any type is used. A single Target message is just for minimal reproducible example.

4

There are 4 best solutions below

0
On

After searching for an answer myself, I found this thread to be the most relevant so I'll post my solution here if it helps anyone (but in Java/Scala).

If you want

repeated google.protobuf.Any targets = 1;

and targets can be any value such as (string, bool, int, etc). This is how I did it in scala/java:

val task = Task.newBuilder()
    .addTargets(Any.pack(StringValue.of("iss")))
    .addTargets(Any.pack(Int32Value.of(25544)))
    .addTargets(Any.pack(DoubleValue.of(1004.882447947814)))
    .addTargets(Any.pack(DoubleValue.of(84.90917890132)))
    .addTargets(Any.pack(DoubleValue.of(14.620929684)))
    .addTargets(Any.pack(StringValue.of("kilometers")))
    .build()
0
On

Thanks @Justin Schoen. According to https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/Any, you need to first create an Any object, then Pack a Target (or any other object type) before appending it to the repeated list.

from google.protobuf.any_pb2 import Any
task = Task()
target = Any()
target.Pack(Target())
task.targets.append(any)
2
On

I have limited knowledge of the any type, but I would think it could be treated as if it were a repeated list of Target messages.

Python Code:

task_targets = []
task_targets.append(<insert_pb2_import>.Target(name='test'))
return <insert_pb2_import>.Task(targets=task_targets)
0
On

After playing around some time I have decided to revise the solution that uses repeating Any. And here is an advice for those who got stuck in this same place: try to use specific types instead of Any.

A workaround for my situation is to create messages of types SpecificTargetSet1, SpecificTargetSet2, etc., that contain specific targets. The Task proto file would look like:

message Task {
    google.protobuf.Any target_set = 1;
}

Target set proto file:

message SpecificTargetSet1 {
    repeated SpecificTarget1 targets = 1;
}

And now a task could be created in such a way:

target = Target()
target.name = "Some name"

target_set = SpecificTargetSet1()
target_set.targets.append(target)

task = Task()
task.target_set.Pack(target_set)

I do not mark my answer as correct, as it is just a workaround.