ネストされた型を含むオブジェクトをシリアル化/逆シリアル化するために使用できるように、protobuf 記述子をサーバーに送信する必要があります。私の問題を示す簡単な例を書きました:
test.proto:
message A {
message B {
required string data = 1;
}
repeated B bs = 1;
}
test.py:
from descriptor_pb2 import DescriptorProto
from google.protobuf import descriptor,reflection,message
from test_pb2 import *
a = A()
b = a.bs.add()
b.data = "stuff"
d1 = a.DESCRIPTOR
dp1 = DescriptorProto()
d1.CopyToProto(dp1)
# dp1 serialized, sent over network, deserialized
d2 = descriptor.MakeDescriptor(dp1)
## This code fixes the problem
#for desc in dp1.nested_type:
# d2.nested_types.append( descriptor.MakeDescriptor(desc) )
#d2.nested_types_by_name = dict((t.name, t) for t in d2.nested_types)
#
#for f in dp1.field:
# d2.fields_by_number[f.number].message_type = d2.nested_types_by_name[f.type_name.split('.')[-1]]
#
## This line cannot be run on the server side
#d2.fields[0].message_type._concrete_class = d1.fields[0].message_type._concrete_class
reflection.ParseMessage(d1, a.SerializeToString())
reflection.ParseMessage(d2, a.SerializeToString())
このコードを実行すると、最後の行でエラーが発生します。
Traceback (most recent call last):
File "test.py", line 29, in <module>
reflection.ParseMessage(d2, a.SerializeToString())
File "build\bdist.win32\egg\google\protobuf\reflection.py", line 168, in ParseMessage
new_msg.ParseFromString(byte_str)
File "build\bdist.win32\egg\google\protobuf\message.py", line 182, in ParseFromString
self.MergeFromString(serialized)
File "build\bdist.win32\egg\google\protobuf\internal\python_message.py", line 795, in MergeFromString
if self._InternalParse(serialized, 0, length) != length:
File "build\bdist.win32\egg\google\protobuf\internal\python_message.py", line 827, in InternalParse
pos = field_decoder(buffer, new_pos, end, self, field_dict)
File "build\bdist.win32\egg\google\protobuf\internal\decoder.py", line 523, in DecodeRepeatedField
if value.add()._InternalParse(buffer, pos, new_pos) != new_pos:
File "build\bdist.win32\egg\google\protobuf\internal\containers.py", line 216, in add
new_element = self._message_descriptor._concrete_class(**kwargs)
AttributeError: 'NoneType' object has no attribute '_concrete_class'
Descriptor.MakeDescriptor() は、デシリアライズされた DescriptorProto からコピーするときに、ネストされたすべての型を完全にコピーしていないためにエラーが発生していることがわかったので、それを補うためにコメント ブロックにコードを記述しました。ただし、最後の行は元の記述子のクラスへの参照を使用しているため、私のサーバーではそれを行うことができません。
私はこの問題を解決するために数え切れないほどの時間を費やしてきましたが、これは私のシステムの非常に重要な部分です。どんな助けでも大歓迎です。