Python: print protobuf spec (fields, types)
If you have a module object corresponding to a module_name_pb2.py
file, or access to the .proto file itself, is there a way to print the spec itself in a pretty way? JSON? I want to show the fields and the types.
I am not looking to print an instance eg, Print human friendly Protobuf message
Given some protobuf message format (Defined in a .proto file) like:
message XYData {
float x = 1;
float y = 2;
}
I am looking for something like:
{
"name" : "XYData",
"fields" : [
{"name" : "x", "type" : "float"},
{"name" : "y", "type" : "float"}
]
}
It would also be nice to be able to list all the messages defined in the .proto file.
EDIT: maybe something like this but in Python: https://github.com/devongovett/protobuf-jsonschema
See the Python module and example protobuf definition here
Given the example protobuf definition:
syntax = "proto3";
message Data1 {
double a = 1;
float b = 2;
int32 c = 3;
int64 d = 4;
bool e = 5;
string f = 6;
bytes g = 7;
}
message Data2 {
Data1 a = 1;
map<string, Data1> b = 2;
map<string, int32> c = 3;
repeated Data1 d = 4;
repeated int32 e = 5;
}
The following is produced:
>>> import test_pb2
>>> msgs = module_msgs(test_pb2)
>>> print(msgs)
{'Data1': Data1(a='TYPE_DOUBLE', b='TYPE_FLOAT', c='TYPE_INT32', d='TYPE_INT64', e='TYPE_BOOL', f='TYPE_STRING', g='TYPE_BYTES'),
'Data2': Data2(a=Data1(a='TYPE_DOUBLE', b='TYPE_FLOAT', c='TYPE_INT32', d='TYPE_INT64', e='TYPE_BOOL', f='TYPE_STRING', g='TYPE_BYTES'), b=Map(key='TYPE_STRING', value=Data1(a='TYPE_DOUBLE', b='TYPE_FLOAT', c='TYPE_INT32', d='TYPE_INT64', e='TYPE_BOOL', f='TYPE_STRING', g='TYPE_BYTES')), c=Map(key='TYPE_STRING', value='TYPE_INT32'), d=Repeated(value=Data1(a='TYPE_DOUBLE', b='TYPE_FLOAT', c='TYPE_INT32', d='TYPE_INT64', e='TYPE_BOOL', f='TYPE_STRING', g='TYPE_BYTES')), e=Repeated(value='TYPE_INT32')),
}
The module_msgs
function takes a protobuf module as input and returns a dict
with message names as keys, and generated namedtuple
objects as values. This is the "top level" function to use.
I used nametuple
types to represent protobuf messages. You can iterate over their fields via the _fields
attribute. In hindsight, perhaps typing.NamedTuple
or collections.OrderedDict
would have been more appropriate.
I created two special namedtuple
s: Map
and Repeated
. You can determine if a field is a map or repeated with isinstance
checks.
The TYPE_* strings correspond to protobuf field types. Thus a protobuf message namedtuple
will have field values that are either strings (corresponding to a protobuf type), a Repeated
or Map
object, or another namedtuple
object.
This has not been tested with other protobuf features, such as default values, Any, Oneof, etc.
See __main__
in the gist for more usage and tests.