Как сериализовать значения по умолчанию во вложенных сообщениях в Protobuf
Как гласит заголовок, у меня есть сообщение protobuf с другим сообщением внутри, например:
syntax = "proto3";
message Message
{
message SubMessage {
int32 number = 1;
}
SubMessage subMessage = 1;
}
мой example.json
пусто (что означает значения по умолчанию везде):
{
}
В моем скрипте Python я прочитал это сообщение с:
with open("example.json", "r") as FH:
exampleJSON = FH.read()
example_message = example.Message()
google.protobuf.json_format.Parse(exampleJSON, example_message)
и когда я проверяю значение example_message.subMessage.number
это 0
что правильно.
Теперь я хочу преобразовать его в dict, где присутствуют все значения - даже значения по умолчанию. Для конвертации я использую метод google.protobuf.json_format.MessageToDict()
, Но, как вы знаете, MessageToDict()
не сериализует значения по умолчанию, пока я не скажу это сделать (как в следующем вопросе: Protobuf не сериализует значения по умолчанию). Поэтому я добавил аргумент including_default_value_fields=True
на зов MessageToDict()
:
protobuf.MessageToDict(example_message, including_default_value_fields=True)
который возвращает:
{}
вместо того, что я ожидал:
{'subMessage': {'number': 0}}
Комментарий в коде protobuf (находится здесь: https://github.com/protocolbuffers/protobuf/blob/master/python/google/protobuf/json_format.py) подтверждает это поведение:
includes_default_value_fields: если True, единичные примитивные поля, повторяющиеся поля и поля карты всегда будут сериализованы. Если False, сериализуют только непустые поля. Эта опция не затрагивает поля единственного сообщения и одно из полей.
Итак, что я могу сделать, чтобы получить dict со всеми значениями, даже если они являются значениями по умолчанию во вложенных сообщениях?
Интересно когда мой example.json
выглядит так:
{
"subMessage" : {
"number" : 0
}
}
Я получаю ожидаемый результат. Но я не могу убедиться, что example.json
будут записаны все значения, так что это не вариант.
1 ответ
Основываясь на ответе атрибутов Looping over Protocol Buffers в Python, я создал пользовательский MessageToDict
функция:
def MessageToDict(message):
messageDict = {}
for descriptor in message.DESCRIPTOR.fields:
key = descriptor.name
value = getattr(message, descriptor.name)
if descriptor.label == descriptor.LABEL_REPEATED:
messageList = []
for subMessage in value:
if descriptor.type == descriptor.TYPE_MESSAGE:
messageList.append(MessageToDict(subMessage))
else:
messageList.append(subMessage)
messageDict[key] = messageList
else:
if descriptor.type == descriptor.TYPE_MESSAGE:
messageDict[key] = MessageToDict(value)
else:
messageDict[key] = value
return messageDict
Учитывая сообщение прочитано из пустого example.json
эта функция возвращает:
{'subMessage': {'number': 0}}