import six from types import GeneratorType as _GeneratorType from google.protobuf.message import Message as _ProtoMessageType if six.PY2: _list_types = list, xrange, _GeneratorType else: _list_types = list, range, _GeneratorType, map, filter protobuf_mask = 0x80000000 def is_proto(emsg): """ :param emsg: emsg number :type emsg: int :return: True or False :rtype: bool """ return (int(emsg) & protobuf_mask) > 0 def set_proto_bit(emsg): """ :param emsg: emsg number :type emsg: int :return: emsg with proto bit set :rtype: int """ return int(emsg) | protobuf_mask def clear_proto_bit(emsg): """ :param emsg: emsg number :type emsg: int :return: emsg with proto bit removed :rtype: int """ return int(emsg) & ~protobuf_mask def proto_to_dict(message): """Converts protobuf message instance to dict :param message: protobuf message instance :return: parameters and their values :rtype: dict :raises: :class:`.TypeError` if ``message`` is not a proto message """ if not isinstance(message, _ProtoMessageType): raise TypeError("Expected `message` to be a instance of protobuf message") data = {} for desc, field in message.ListFields(): if desc.type == desc.TYPE_MESSAGE: if desc.label == desc.LABEL_REPEATED: data[desc.name] = list(map(proto_to_dict, field)) else: data[desc.name] = proto_to_dict(field) else: data[desc.name] = list(field) if desc.label == desc.LABEL_REPEATED else field return data def proto_fill_from_dict(message, data, clear=True): """Fills protobuf message parameters inplace from a :class:`dict` :param message: protobuf message instance :param data: parameters and values :type data: dict :param clear: whether clear exisiting values :type clear: bool :return: value of message paramater :raises: incorrect types or values will raise """ if not isinstance(message, _ProtoMessageType): raise TypeError("Expected `message` to be a instance of protobuf message") if not isinstance(data, dict): raise TypeError("Expected `data` to be of type `dict`") if clear: message.Clear() field_descs = message.DESCRIPTOR.fields_by_name for key, val in data.items(): desc = field_descs[key] if desc.type == desc.TYPE_MESSAGE: if desc.label == desc.LABEL_REPEATED: if not isinstance(val, _list_types): raise TypeError("Expected %s to be of type list, got %s" % (repr(key), type(val))) list_ref = getattr(message, key) # Takes care of overwriting list fields when merging partial data (clear=False) if not clear: del list_ref[:] # clears the list for item in val: item_message = getattr(message, key).add() proto_fill_from_dict(item_message, item) else: if not isinstance(val, dict): raise TypeError("Expected %s to be of type dict, got %s" % (repr(key), type(dict))) proto_fill_from_dict(getattr(message, key), val) else: if isinstance(val, _list_types): list_ref = getattr(message, key) if not clear: del list_ref[:] # clears the list list_ref.extend(val) else: setattr(message, key, val) return message