Создайте сообщение буфера протокола, только зная его имя типа - PullRequest
0 голосов
/ 23 сентября 2019

Для задачи отладки я хотел бы читать / записывать сообщения буфера протокола с динамическим импортом файлов, сгенерированных буферами протокола.

Я занимаюсь разработкой приложения, в котором многие задачи будут обмениваться данными с использованием буфера протокола.AMQP.В настоящее время я работаю над задачей отладки Python, которая должна иметь возможность подключаться к любому каналу и отображать обмен данными.Я хочу избежать какой-либо зависимости между этой задачей и файлами .proto.

Решение основано на следующем принципе: - На этапе разработки файлы .proto компилируются в каталог - Задача отладкидинамически импортирует эти файлы ( _pb2.py) - во время выполнения сообщения AMQP содержат имя сообщения и закодированное сообщение.Задача отладки должна иметь возможность динамически создавать сообщение из его имени и его содержимого.

Решение, которое я нашел, работает, но требует вызова eval ().

def ImportPath(path):
    messageFactory = dict()
    # Browse directory to find protobuf compiled files
    sys.path.append(os.path.join(os.path.dirname(__file__), path))
    modulesNames = [f for f in os.listdir(path) if re.match(r'.*_pb2.py', f) ]
    # for each file, creatre an entry in the factory
    for moduleName in modulesNames:
        # remove extension
        mod = moduleName[:-3]
        print ("Import:" + str(mod))
        # import module
        module = __import__(mod)
        for i in module.DESCRIPTOR.message_types_by_name:
            print ("Add:"+str(i)+" to messageFactory")
            # Is there a better way to do this ? 
            messageFactory[i]=eval("module."+i+"()")
    return messageFactory

messageFactory = ImportPath('.')

# test case
def PrepareTestCase():
    proto = 'syntax = "proto2"; message Person { required string name = 1; required int32 id = 2; optional string email = 3;}'
    with open('Person.proto','w') as f:
        f.write(proto)
    os.system('protoc -I=. --python_out=. Person.proto')

def GenericReader(messageType,message):
    msg = messageFactory[messageType]
    msg.ParseFromString(message)
    fieldnames = [ field.name for field in msg.DESCRIPTOR.fields ]
    print("GenericReader("+messageType+")")
    for fieldname in fieldnames:
        s = fieldname + " : ";
        if not msg.HasField(fieldname):
            s = s + "(NotSet)"
        s = s+str(getattr(msg, fieldname))
        print(s)

PrepareTestCase()
msg1 = messageFactory['Person']
msg1.name = bytes('Sir Lancelot the Brave','UTF-8');
msg1.id = 2;
msg1.email = bytes('lancelot@camelot.uk','UTF-8');
message = msg1.SerializeToString()
GenericReader('Person',message)

Есть лилучший способ достичь этого?

...