4

How does one get the options associated with a protocol buffer field?

E.g., suppose I have a field with a custom options:

message Foo {
  optional string title = 1 [(indexed) = true];
}

I can get a list of fields:

for f in foo.ListFields():
  print f

How do I access the "indexed" state? (I can see there is a list of f "_options", but that seems "internal"? Is there a proper way to access option extensions by name)?

1
  • I don't think so. What do you want to achieve? Commented Sep 29, 2015 at 10:02

1 Answer 1

14

I'll use as an example the nanopb custom options, as defined here. However the answer itself is not in any way nanopb-specific, nanopb uses the standard protobuf style for custom options:

message NanoPBOptions {
   optional int32 max_size = 1;
   ...
}
extend google.protobuf.FieldOptions {
   optional NanoPBOptions nanopb = 1010;
}

and an option defined like this:

message Person {
   optional string email = 3 [(nanopb).max_size = 40];
}

The API used to get the option value varies between languages. However the basic flow is the same:

  1. Get the message descriptor from the object.
  2. Get the field descriptor from the message descriptor.
  3. Get the options from the field descriptor.
  4. Get the extension field from the options, and the value you want from that.

In Python:

desc = person_pb2.Person.DESCRIPTOR
field_desc = desc.fields_by_name['email']
options = field_desc.GetOptions()
value = options.Extensions[nanopb_pb2.nanopb].max_size

In Java:

desc = PersonProto.Person.getDescriptor();
field_desc = desc.findFieldByName("email");
options = field_desc.getOptions();
value = options.getExtension(Nanopb.nanopb).getMaxSize();

In C++:

desc = Person::descriptor()
field_desc = desc->FindFieldByName("email");
options = field_desc->options();
value = options.GetExtension(nanopb).max_size());
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you for your explanation. I am trying to make this work and am having some trouble. First, a simple question: we need to first run protoc on the proto file defining the options to get the compiled version (in this case, we run protoc to get nanopb_pb2.py. Is there any way of doing this on the fly (i.e. oh I need these custom options, let me compile their proto so I can access them)? Secondly, when I access field_desc.options.Extensions[nanopb_pb2.nanopb].max_size I get 0. Any ideas as to what I may be doing wrong?
I see, you are accessing after compiling with protoc. I am trying to access from within a protoc plugin.
@LoveToCode Protoc plugins work so that protoc first processes the file and then passes it to the plugin, so the differences are quite small. See main_plugin function.
the part I am not understanding is that in order for the custom options to be loaded, the plugin must have imported the extension (i.e. import nanopb_pb2) as generated by the default plugin before calling CodeGeneratorRequest.ParseFromString, but how is the plugin going to know what it needs to import before calling CodeGeneratorRequest.ParseFromString?
@LoveToCode Well, usually your code would know what kind of options it cares about, import the definitions for all of them and ignore other options. But the unknown fields mechanism should give access to options that you can't parse.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.