你能帮助我理解为什么会崩溃吗:我正在尝试使用protobuf ParseDict函数将Python对象的结构转换为单个Protocol Buffer对象。
作为实验,我尝试制作一些protobuf实例,将它们转换为字典结构,然后再将它们转换回protobuf。
我写了以下代码:
msg0=MsgGrpType.MsgType(subject="test_subject0")
msg1=MsgGrpType.MsgType(subject="test_subject1")
msg2=MsgGrpType.MsgType(subject="test_subject3")
msgGrp = MsgGrpType(flow="BOALF", msg=[msg0,msg1,msg2], pub_ts=datetime.datetime.now().isoformat())
msgDict = google.protobuf.json_format.MessageToDict(msgGrp)
result = ParseDict(msgDict, MsgGrpType, ignore_unknown_fields=True) # Crashes
pprint.pprint(result)
当我运行该脚本时,msgDict具有以下结构:
{'flow': 'BOALF',
'msg': [{'subject': 'test_subject0'},
{'subject': 'test_subject1'},
{'subject': 'test_subject3'}],
'pubTs': '2021-07-19T13:18:40.263824'}
脚本崩溃,并显示以下错误:
self = <google.protobuf.json_format._Parser object at 0x0000020177A3F2E0>
js = {'flow': 'BOALF', 'msg': [{'subject': 'test_subject0'}, {'subject': 'test_subject1'}, {'subject': 'test_subject3'}], 'pubTs': '2021-07-19T13:18:40.263824'}
message = <class 'com_elexeon_boalf_pb2.MsgGrpType'>
def _ConvertFieldValuePair(self, js, message):
"""Convert field value pairs into regular message.
Args:
js: A JSON object to convert the field value pairs.
message: A regular protocol message to record the data.
Raises:
ParseError: In case of problems converting.
"""
names = []
message_descriptor = message.DESCRIPTOR
fields_by_json_name = dict((f.json_name, f)
for f in message_descriptor.fields)
for name in js:
try:
field = fields_by_json_name.get(name, None)
if not field:
field = message_descriptor.fields_by_name.get(name, None)
if not field and _VALID_EXTENSION_NAME.match(name):
if not message_descriptor.is_extendable:
raise ParseError('Message type {0} does not have extensions'.format(
message_descriptor.full_name))
identifier = name[1:-1] # strip [] brackets
# pylint: disable=protected-access
field = message.Extensions._FindExtensionByName(identifier)
# pylint: enable=protected-access
if not field:
# Try looking for extension by the message type name, dropping the
# field name following the final . separator in full_name.
identifier = '.'.join(identifier.split('.')[:-1])
# pylint: disable=protected-access
field = message.Extensions._FindExtensionByName(identifier)
# pylint: enable=protected-access
if not field:
if self.ignore_unknown_fields:
continue
raise ParseError(
('Message type "{0}" has no field named "{1}".\n'
' Available Fields(except extensions): {2}').format(
message_descriptor.full_name, name,
[f.json_name for f in message_descriptor.fields]))
if name in names:
raise ParseError('Message type "{0}" should not have multiple '
'"{1}" fields.'.format(
message.DESCRIPTOR.full_name, name))
names.append(name)
value = js[name]
# Check no other oneof field is parsed.
if field.containing_oneof is not None and value is not None:
oneof_name = field.containing_oneof.name
if oneof_name in names:
raise ParseError('Message type "{0}" should not have multiple '
'"{1}" oneof fields.'.format(
message.DESCRIPTOR.full_name, oneof_name))
names.append(oneof_name)
if value is None:
if (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE
and field.message_type.full_name == 'google.protobuf.Value'):
sub_message = getattr(message, field.name)
sub_message.null_value = 0
elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM
and field.enum_type.full_name == 'google.protobuf.NullValue'):
setattr(message, field.name, 0)
else:
message.ClearField(field.name)
continue
# Parse field value.
if _IsMapEntry(field):
message.ClearField(field.name)
self._ConvertMapFieldValue(value, message, field)
elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
> message.ClearField(field.name)
E TypeError: descriptor 'ClearField' for 'google.protobuf.pyext._message.CMessage' objects doesn't apply to a 'str' object
C:\installs\anaconda\envs\eunrg_elexeon_protobufs\lib\site-packages\google\protobuf\json_format.py:561: TypeError
During handling of the above exception, another exception occurred:
def test3():
msg0=MsgGrpType.MsgType(subject="test_subject0")
msg1=MsgGrpType.MsgType(subject="test_subject1")
msg2=MsgGrpType.MsgType(subject="test_subject3")
msgGrp = MsgGrpType(flow="BOALF", msg=[msg0,msg1,msg2], pub_ts=datetime.datetime.now().isoformat())
msgDict = google.protobuf.json_format.MessageToDict(msgGrp)
pprint.pprint(msgDict)
> result = ParseDict(msgDict, MsgGrpType, ignore_unknown_fields=True) # Crashes
test_boalf.py:52:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
C:\installs\anaconda\envs\eunrg_elexeon_protobufs\lib\site-packages\google\protobuf\json_format.py:454: in ParseDict
parser.ConvertMessage(js_dict, message)
C:\installs\anaconda\envs\eunrg_elexeon_protobufs\lib\site-packages\google\protobuf\json_format.py:485: in ConvertMessage
self._ConvertFieldValuePair(value, message)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <google.protobuf.json_format._Parser object at 0x0000020177A3F2E0>
js = {'flow': 'BOALF', 'msg': [{'subject': 'test_subject0'}, {'subject': 'test_subject1'}, {'subject': 'test_subject3'}], 'pubTs': '2021-07-19T13:18:40.263824'}
message = <class 'com_elexeon_boalf_pb2.MsgGrpType'>
def _ConvertFieldValuePair(self, js, message):
"""Convert field value pairs into regular message.
Args:
js: A JSON object to convert the field value pairs.
message: A regular protocol message to record the data.
Raises:
ParseError: In case of problems converting.
"""
names = []
message_descriptor = message.DESCRIPTOR
fields_by_json_name = dict((f.json_name, f)
for f in message_descriptor.fields)
for name in js:
try:
field = fields_by_json_name.get(name, None)
if not field:
field = message_descriptor.fields_by_name.get(name, None)
if not field and _VALID_EXTENSION_NAME.match(name):
if not message_descriptor.is_extendable:
raise ParseError('Message type {0} does not have extensions'.format(
message_descriptor.full_name))
identifier = name[1:-1] # strip [] brackets
# pylint: disable=protected-access
field = message.Extensions._FindExtensionByName(identifier)
# pylint: enable=protected-access
if not field:
# Try looking for extension by the message type name, dropping the
# field name following the final . separator in full_name.
identifier = '.'.join(identifier.split('.')[:-1])
# pylint: disable=protected-access
field = message.Extensions._FindExtensionByName(identifier)
# pylint: enable=protected-access
if not field:
if self.ignore_unknown_fields:
continue
raise ParseError(
('Message type "{0}" has no field named "{1}".\n'
' Available Fields(except extensions): {2}').format(
message_descriptor.full_name, name,
[f.json_name for f in message_descriptor.fields]))
if name in names:
raise ParseError('Message type "{0}" should not have multiple '
'"{1}" fields.'.format(
message.DESCRIPTOR.full_name, name))
names.append(name)
value = js[name]
# Check no other oneof field is parsed.
if field.containing_oneof is not None and value is not None:
oneof_name = field.containing_oneof.name
if oneof_name in names:
raise ParseError('Message type "{0}" should not have multiple '
'"{1}" oneof fields.'.format(
message.DESCRIPTOR.full_name, oneof_name))
names.append(oneof_name)
if value is None:
if (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE
and field.message_type.full_name == 'google.protobuf.Value'):
sub_message = getattr(message, field.name)
sub_message.null_value = 0
elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM
and field.enum_type.full_name == 'google.protobuf.NullValue'):
setattr(message, field.name, 0)
else:
message.ClearField(field.name)
continue
# Parse field value.
if _IsMapEntry(field):
message.ClearField(field.name)
self._ConvertMapFieldValue(value, message, field)
elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
message.ClearField(field.name)
if not isinstance(value, list):
raise ParseError('repeated field {0} must be in [] which is '
'{1}.'.format(name, value))
if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
# Repeated message field.
for item in value:
sub_message = getattr(message, field.name).add()
# None is a null_value in Value.
if (item is None and
sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'):
raise ParseError('null is not allowed to be used as an element'
' in a repeated field.')
self.ConvertMessage(item, sub_message)
else:
# Repeated scalar field.
for item in value:
if item is None:
raise ParseError('null is not allowed to be used as an element'
' in a repeated field.')
getattr(message, field.name).append(
_ConvertScalarFieldValue(item, field))
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
if field.is_extension:
sub_message = message.Extensions[field]
else:
sub_message = getattr(message, field.name)
sub_message.SetInParent()
self.ConvertMessage(value, sub_message)
else:
if field.is_extension:
message.Extensions[field] = _ConvertScalarFieldValue(value, field)
else:
setattr(message, field.name, _ConvertScalarFieldValue(value, field))
except ParseError as e:
if field and field.containing_oneof is None:
raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
else:
raise ParseError(str(e))
except ValueError as e:
raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
except TypeError as e:
> raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
E google.protobuf.json_format.ParseError: Failed to parse msg field: descriptor 'ClearField' for 'google.protobuf.pyext._message.CMessage' objects doesn't apply to a 'str' object.
这是我的.proto文件:
// com_elexeon_boalf.proto at 0:0
syntax = "proto3";
package com.elexeon.boalf;
message MsgGrpType {
string pub_ts = 1;
string flow = 2;
repeated MsgType msg = 3;
message MsgType {
string subject = 1;
int32 n_k = 2;
string s_o = 3;
string p_f = 4;
string t_a = 5;
string a_d = 6;
int32 n_p = 7;
repeated RowType row = 8;
message RowType {
string t_s = 1;
double v_a = 2;
}
}
}
发布于 2021-08-08 00:17:51
google.protobuf.json_format.ParseDict函数将合并结果的消息作为其第二个参数。然后,它返回该消息。在您的示例中,您为它指定了一个类型(MsgGrpType
)。如果希望将结果合并到frew new ("empty")消息中,则需要将MsgGrpType
更改为MsgGrpType()
,以便将类的一个新实例传递给ParseDict
。
(不幸的是,错误消息相当模糊。)
下面的Python片段似乎可以按预期工作:
from com_elexeon_boalf_pb2 import MsgGrpType
import datetime
from google.protobuf.json_format import MessageToDict, ParseDict
import pprint
msg0=MsgGrpType.MsgType(subject="test_subject0")
msg1=MsgGrpType.MsgType(subject="test_subject1")
msg2=MsgGrpType.MsgType(subject="test_subject3")
msgGrp = MsgGrpType(flow="BOALF", msg=[msg0,msg1,msg2], pub_ts=datetime.datetime.now().isoformat())
msgDict = MessageToDict(msgGrp)
result = ParseDict(msgDict, MsgGrpType(), ignore_unknown_fields=True)
pprint.pprint(result)
执行时生成以下输出:
pub_ts: "2021-08-08T01:15:44.232683"
flow: "BOALF"
msg {
subject: "test_subject0"
}
msg {
subject: "test_subject1"
}
msg {
subject: "test_subject3"
}
https://stackoverflow.com/questions/68440156
复制相似问题