Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using google.protobuf.Any in python file

I have such .proto file

syntax = "proto3";
import "google/protobuf/any.proto";

message Request {
  google.protobuf.Any request_parameters = 1;
}

How can I create Request object and populate its fields? I tried this:

import ma_pb2
from google.protobuf.any_pb2 import Any

parameters = {"a": 1, "b": 2}
Request = ma_pb2.Request()
some_any = Any()
some_any.CopyFrom(parameters)
Request.request_parameters = some_any

But I have an error:

TypeError: Parameter to CopyFrom() must be instance of same class: expected google.protobuf.Any got dict.

UPDATE

Following prompts of @Kevin I added new message to .proto file:

message Small {
  string a = 1;
}

Now code looks like this:

Request = ma_pb2.Request()
small = ma_pb2.Small()
small.a = "1"

some_any = Any()
some_any.Pack(small)

Request.request_parameters = small

But at the last assignment I have an error:

Request.request_parameters = small
AttributeError: Assignment not allowed to field "request_parameters" in protocol message object.

What did I do wrong?

like image 328
Kenenbek Arzymatov Avatar asked May 06 '17 19:05

Kenenbek Arzymatov


People also ask

How do you use any in Protobuf?

To use the Any type, you must import the google/protobuf/any. proto definition. In the C# code, the Any class provides methods for setting the field, extracting the message, and checking the type. Protobuf's internal reflection code uses the Descriptor static field on each generated type to resolve Any field types.

How do you Protobuf in Python?

Before creating the proto file, we need to install the proto compiler known as protoc. To install it, visit Github and download the python protoc compiler. We have installed the 64 bit version window. It will download the protoc compiler in the system.

What is Google Protobuf any?

Any contains an arbitrary serialized protocol buffer message along with a URL that describes the type of the serialized message. Protobuf library provides support to pack/unpack Any values in the form of utility functions or additional generated methods of the Any type.


1 Answers

Any is not a magic box for storing arbitrary keys and values. The purpose of Any is to denote "any" message type, in cases where you might not know which message you want to use until runtime. But at runtime, you still need to have some specific message in mind. You can then use the .Pack() and .Unpack() methods to convert that message into an Any, and at that point you would do something like Request.request_parameters.CopyFrom(some_any).

So, if you want to store this specific dictionary:

{"a": 1, "b": 2}

...you'll need a .proto file which describes some message type that has integer fields named a and b. Personally, I'd see that as overkill; just throw your a and b fields directly into the Request message, unless you have a good reason for separating them out. If you "forget" one of these keys, you can always add it later, so don't worry too much about completeness.


If you really want a "magic box for storing arbitrary keys and values" rather than what I described above, you could use a Map instead of Any. This has the advantage of not requiring you to declare all of your keys upfront, in cases where the set of keys might include arbitrary strings (for example, HTTP headers). It has the disadvantage of being harder to lint or type-check (especially in statically-typed languages), because you can misspell a string more easily than an attribute. As shown in the linked resource, Maps are basically syntactic sugar for a repeated field like the following (that is, the on-wire representation is exactly the same as what you'd get from doing this, so it's backwards compatible to clients which don't support Maps):

message MapFieldEntry {
  key_type key = 1;
  value_type value = 2;
}

repeated MapFieldEntry map_field = N;
like image 142
Kevin Avatar answered Sep 22 '22 15:09

Kevin