Self-describing messages in Python

603 views
Skip to first unread message

Jan Machek

unread,
Apr 7, 2023, 5:38:50 PM4/7/23
to Protocol Buffers
Hello,

I am trying to build self-describing messages using Python. I read through the documentation https://protobuf.dev/programming-guides/techniques/#self-description as well as through the Python API https://googleapis.dev/python/protobuf/latest/google/protobuf.html, but I am still not very sure about how to do that.

I started with the example message 
syntax = "proto3"; import "google/protobuf/any.proto"; import "google/protobuf/descriptor.proto"; message SelfDescribingMessage { // Set of FileDescriptorProtos which describe the type and its dependencies. google.protobuf.FileDescriptorSet descriptor_set = 1; // The message and its type, encoded as an Any message. google.protobuf.Any message = 2; }

And I would like to pass through it a simple addressbook message

syntax = "proto2";

package tutorial;

message AddressBook {
  optional string name = 1;
  optional string number = 2;
}


The AddressBook message would be contained in the message field and the descriptor_set field would contain the descriptor of the proto above.

However I could not do this no matter what I have tried.

The closest I got was exporting a file descriptor set from the SelfDescribingMessage.proto given in the documentation as "protoc --proto_path=. --proto_path=./include --descriptor_set_out=./self_describing_ds --include_imports self_describing.proto" and then reading it

with open("self_describing_ds", 'rb') as fh:
        fds = descriptor_pb2.FileDescriptorSet.FromString(fh.read())

message_classes = message_factory.GetMessages(fds.file)
my_proto_instance = message_classes["SelfDescribingMessage"]()

address_book = addressbook_pb2.AddressBook()
address_book.name = "John Doe"
address_book.number = "123456"

my_proto_instance.message.Pack(address_book)

I am not able to set my_proto_instance.descriptor_set though. Extracting address book descriptor set using protoc and then reading it and trying to append it 

with open("addressbook_ds", 'rb') as fh:
        addressbook_fds = descriptor_pb2.FileDescriptorSet.FromString(fh.read()) 
my_proto_instance.descriptor_set.file.append(addressbook_fds)

fails on

TypeError: Parameter to MergeFrom() must be instance of same class: expected <class 'FileDescriptorProto'> got <class 'google.protobuf.descriptor_pb2.FileDescriptorProto'>.

I could not get any closer.

Does anyone have any simple example on sending the self-describing messages in Python, please?

Thanks a lot in advance.

Jan




Jan Machek

unread,
Jun 15, 2023, 8:34:22 AM6/15/23
to Protocol Buffers
Hello,

in the end I managed to fix this issue using CopyFrom(fds), where fds is an instnce of google.protobuf.descriptor_pb2.FileDescriptorSet, rather than file.append function as show in my original code.

So in the code above we would call my_proto_instance.descriptor_set.CopyFrom(addressbook_fds)  instead of my_proto_instance.descriptor_set.file.append(addressbook_fds).

Hope someone finds this useful.

Cheers

Jan
Reply all
Reply to author
Forward
0 new messages