为动态生成的消息创建 protobuf 工厂?

问题描述 投票:0回答:1

基于动态创建新的protobuf消息,我有这个Python代码,它动态生成一个包含两个整数和一个字符串的protobuf。 (上下文:动态数据服务器将通过 protobuf 传输查询结果。)

我可以正确创建描述符,并且我相信用于实例化和填充消息类的代码是正确的。

但是,当尝试生成工厂时

# Step 5: Create the message class                                             
factory = message_factory.MessageFactory(pool)                                 
DynamicMessageClass = factory.GetPrototype(message_descriptor) <-- error here               

我收到此错误。

/Users/mark/g/private/lessons/proto_dynamic/g2.py:40: UserWarning: MessageFactory class is deprecated. Please use GetMessageClass() instead of MessageFactory.GetPrototype. MessageFactory class will be removed after 2024.
  DynamicMessageClass = factory.GetPrototype(message_descriptor)
Traceback (most recent call last):
  File "/Users/mark/g/private/lessons/proto_dynamic/g2.py", line 40, in <module>
    DynamicMessageClass = factory.GetPrototype(message_descriptor)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/mark/miniconda3/lib/python3.11/site-packages/google/protobuf/message_factory.py", line 185, in GetPrototype
    return GetMessageClass(descriptor)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/mark/miniconda3/lib/python3.11/site-packages/google/protobuf/message_factory.py", line 70, in GetMessageClass
    concrete_class = getattr(descriptor, '_concrete_class', None)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: No message class registered for 'dynamic_package.DynamicMessage'

我需要做什么才能从我的描述符生成我的类?

完整代码,供参考:

from google.protobuf import descriptor_pb2, descriptor_pool, message_factory   
                                                                               
# Step 1: Create the DescriptorProto for the message                           
message_descriptor_proto = descriptor_pb2.DescriptorProto()                    
message_descriptor_proto.name = "DynamicMessage"                               
message_descriptor_proto.field.add(                                            
    name="first_int",                                                          
    number=1,                                                                  
    type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32,                       
    label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL,                  
)                                                                              
message_descriptor_proto.field.add(                                            
    name="second_int",                                                         
    number=2,                                                                  
    type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32,                       
    label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL,                  
)                                                                              
message_descriptor_proto.field.add(                                            
    name="a_string",                                                           
    number=3,                                                                  
    type=descriptor_pb2.FieldDescriptorProto.TYPE_STRING,                      
    label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL,                  
)                                                                              
                                                                               
# Step 2: Create a FileDescriptorProto including the DescriptorProto           
file_descriptor_proto = descriptor_pb2.FileDescriptorProto()                   
file_descriptor_proto.name = "dynamic_message.proto"                           
file_descriptor_proto.package = "dynamic_package"                              
file_descriptor_proto.message_type.add().CopyFrom(message_descriptor_proto)    
                                                                               
# Step 3: Add the FileDescriptorProto to a DescriptorPool                      
pool = descriptor_pool.DescriptorPool()                                        
file_descriptor = pool.Add(file_descriptor_proto)                              
                                                                               
# Step 4: Retrieve the message descriptor by name from the DescriptorPool      
message_descriptor = pool.FindMessageTypeByName("dynamic_package.DynamicMessage")
                                                                               
# Step 5: Create the message class                                             
factory = message_factory.MessageFactory(pool)                                 
DynamicMessageClass = factory.GetPrototype(message_descriptor)                 
                                                                               
# Step 6: Instantiate the message class and populate with data                 
dynamic_message = DynamicMessageClass()                                        
dynamic_message.first_int = 123                                                
dynamic_message.second_int = 456                                               
dynamic_message.a_string = "Hello, World!"                                     
                                                                               
# Serialize the message to a byte string                                       
serialized_data = dynamic_message.SerializeToString()                          
                                                                               
# Show the serialized data                                                     
print(serialized_data)                                                         
python protocol-buffers
1个回答
0
投票

答案来自message_factory模块的文档:

Provides a factory class for generating dynamic messages.

The easiest way to use this class is if you have access to the FileDescriptor
protos containing the messages you want to create you can just do the following:

message_classes = message_factory.GetMessages(iterable_of_file_descriptors)
my_proto_instance = message_classes['some.proto.package.MessageName']()

因此,使其发挥作用的一种方法是:

dynamic_message = message_factory.GetMessages([file_descriptor_proto])['dynamic_package.DynamicMessage']()
dynamic_message.first_int = 123
dynamic_message.second_int = 456
dynamic_message.a_string = "Hello, World!"
print(dynamic_message)
first_int: 123
second_int: 456
a_string: "Hello, World!"

这里的

file_descriptor_proto
是在第二步结束时生成的。

© www.soinside.com 2019 - 2024. All rights reserved.