简体   繁体   中英

How to get the type of a variable defined in a protobuf message?

I'm trying to do some 'translation' from protobuf files to Objective-C classes using Python. For example, given the protobuf message:

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;
}

I want to translate it into an objc class:

@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int ID;
@property (nonatomic, copy) NSString *email; 
@end

The key point is to acquire every property's name and type. For example, 'optional string email' in the protobuf message, its name is 'email', type is 'string', so it should be NSString *email in objective-c. I followed the official tutorial, wrote an addressbook.proto just the same as the one in the tutorial and compiled it. Then I wrote my python code:

import addressbook_pb2 as addressbook

p = addressbook.Person()
all_fields = p.DESCRIPTOR.fields_by_name
# print "all fields: %s" %all_fields
field_keys = all_fields.keys()
# print "all keys: %s" %field_keys

for key in field_keys:
    one_field = all_fields[key]
    print one_field.label

This just gave me:

1
2
3
2

So I guess label is not what I need, while field_keys is just the list of names that I expect. I tried some other words, and did some search on the web, but didn't find the right answer.

If there's no way to acquire the type, I have another thought, which is to read and analyze every line of the protobuf source file in a pure 'Pythonic' way, but I really don't want to do this if its not necessary.

Can anybody help me?

The FieldDescriptor class has a message_type member which, if a composite field, is a descriptor of the message type contained in this field. Otherwise, this is None.

Combine this with iterating through a dictionary of DESCRIPTORS means you can get the name and type of composite and non-composite (raw) fields.

import addressbook_pb2 as addressbook
DESCRIPTORS = addressbook.Person.DESCRIPTOR.fields_by_name

for (field_name, field_descriptor) in DESCRIPTORS.items():

    if field_descriptor.message_type:
        # Composite field
        print(field_name, field_descriptor.message_type.name)
    else:
        # Raw type
        print(field_name, field_descriptor.type)
        # TYPE_DOUBLE
        # TYPE_FLOAT 
        # TYPE_INT64 
        # TYPE_UINT64
        # TYPE_INT32 
        # TYPE_FIXED64
        # TYPE_FIXED32
        # TYPE_BOOL  
        # TYPE_STRING
        # TYPE_GROUP
        # TYPE_MESSAGE
        # TYPE_BYTES
        # TYPE_UINT32
        # TYPE_ENUM
        # TYPE_SFIXED32
        # TYPE_SFIXED64
        # TYPE_SINT32
        # TYPE_SINT64
        # MAX_TYPE

The raw types are class attributes; https://github.com/protocolbuffers/protobuf/blob/master/python/google/protobuf/descriptor.py

Thanks to Marc's answer, I figured out some solution. This is just a thought, but it's a huge step for me.

Python code:

import addressbook_pb2 as addressbook

typeDict = {"1":"CGFloat", "2":"CGFloat", "3":"NSInteger", "4":"NSUinteger", "5":"NSInteger", "8":"BOOL", "9":"NSString", "13":"NSUinteger", "17":"NSInteger", "18":"NSInteger"}

attrDict = {"CGFloat":"assign", "NSInteger":"assign", "NSUinteger":"assign", "BOOL":"assign", "NSString":"copy"}

p = addressbook.Person()
all_fields = p.DESCRIPTOR.fields_by_name
field_keys = all_fields.keys()
for key in field_keys:
    one_field = all_fields[key]
    typeNumStr = str(one_field.type)
    className = typeDict.get(typeNumStr, "NSObject")
    attrStr = attrDict.get(className, "retain")
    propertyStr = "@property (nonatomic, %s) %s *%s" %(attrStr, className, key)
    print propertyStr

For the addressbook example, it prints:

@property (nonatomic, copy) NSString *email
@property (nonatomic, copy) NSString *name
@property (nonatomic, retain) NSObject *phone
@property (nonatomic, assign) NSInteger *id

Not the final solution, but it means a lot. Thank you, Marc!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM