Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize Protobuf in python from class name

How can I deserialize a protocol buffer message, knowing only the string name of the protoc-generated class?

For some reason, the fully qualified name of the message that I get with DESCRIPTOR.full_name does not match the actual location of the python class, so I am unable to deserialize it with the following function:

def get_class( kls ):
    """Get class given a fully qualified name of a class"""
    parts = kls.split('.')
    module = ".".join(parts[:-1])
    m = __import__( module )
    for comp in parts[1:]:
        m = getattr(m, comp)
    return m

I just get ImportError no module (name).

Any help appreciated.

P.S.: In case it helps, the bigger problem I am trying to solve is to serialize the protobuf message to the database, and then deserialize it back out (I am using postgresql with sqlalchemy in this case). Since regular python pickle doesn't work - I am hoping to store a tuple (message_cls_name, message_binary) where message_cls_name is a fully qualified name of the protobuf message, and message_binary is a result of called SerializeToString on the message. The part I am not clear about is how to get the message out and deserialize it into proper protobuf class.

like image 233
Andriy Drozdyuk Avatar asked Dec 19 '22 06:12

Andriy Drozdyuk


1 Answers

Here is an example solution..

from ocmg_common.protobuf.rpc_pb2 import Exception as PBException
from importlib import import_module

pb_message = PBException(message='hello world')
pb_message_string = pb_message.SerializeToString()

def deserialize(message, typ):
    module_, class_ = typ.rsplit('.', 1)
    class_ = getattr(import_module(module_), class_)
    rv = class_()
    rv.ParseFromString(message)
    return rv

print(deserialize(pb_message_string, 'ocmg_common.protobuf.rpc_pb2.Exception'))

will output

(env)➜ httppost git:(master) ✗ python test.py
message: "hello world"

If you dont know the module, but only have the DESCRIPTOR.full_name you have to name them the same way, or create a function that maps a full descriptor name to a module. Otherwise you are stuck and dont know from where to import the module.

I hope it will help you.. ;)
Best of luck..

like image 177
brunsgaard Avatar answered Dec 22 '22 01:12

brunsgaard