def _deserializeMessageField(self, message, field, data): """ Mutates C{message} based on C{data} and C{field}. C{message} is a L{google.protobuf.message.Message}. C{field} is a L{google.protobuf.descriptor.FieldDescriptor}. C{data} is a L{list}, L{int}, L{long}, L{float}, L{bool}, L{str}, L{unicode}, or L{NoneType}. """ isBool = (field.type == TYPE_BOOL) isEnum = (field.type == TYPE_ENUM) if field.label == LABEL_REPEATED: messageField = getattr(message, field.name) if field.type not in MESSAGE_OR_GROUP: for value in _getIterator(data): if isBool: value = _convertToBool(value) elif isEnum: _ensureValidEnum(field, value) try: messageField.append(value) except (TypeError, ValueError), e: raise PbDecodeError(str(e)) else: for subdata in _getIterator(data): self._deserializeMessage(messageField.add(), subdata)
def _deserializeMessage(self, message, data): """ Mutates C{message} based on C{data}. C{message} is a L{google.protobuf.message.Message}. C{data} is a L{list}. """ for tag, field in message.DESCRIPTOR.fields_by_number.iteritems(): try: subdata = data[tag] except IndexError: if tag > (len(data) - 1) and field.label == FieldDescriptor.LABEL_OPTIONAL: # Deals with the fact that the js pblite serializer leaves off # null optional fields at the end of a message. The len(data) must # be adjusted because there's always a null value in the first position # and because tags are 1-indexed by default. # # Since these fields are null, we don't bother deserializing them. # Plus if we did, the value of subdata would be wrong. continue else: raise PbDecodeError("For message %r expected index " "%r but it was missing." % (message, tag)) self._deserializeMessageField(message, field, subdata)
def _getIterator(obj): """ Returns C{obj.__iter__()} or raises a L{PbDecodeError}. """ try: return obj.__iter__() except (TypeError, AttributeError): raise PbDecodeError("Expected an iterable object but " "found a %r" % (type(obj), ))
def _ensureValidEnum(field, obj): # Protocol Buffers' Python module (as of 2010-07-18) allows setting # an enum field to an invalid value. This can lead to all sorts of # terrible bugs. Here we dig into the field and check if the value is # allowed. I filed a bug to get this fixed in protobuf: # https://code.google.com/p/protobuf/issues/detail?id=206 if obj not in field.enum_type.values_by_number: raise PbDecodeError("Expected a valid value for " "%r, but didn't get one." % (field, ))
def _deserializeMessage(self, message, data): """ Mutates C{message} based on C{data}. C{message} is a L{google.protobuf.message.Message}. C{data} is a L{list}. """ for tag, field in message.DESCRIPTOR.fields_by_number.iteritems(): try: subdata = data[tag] except IndexError: # Raise even if it was an optional field. raise PbDecodeError("For message %r expected index " "%r but it was missing." % (message, tag)) self._deserializeMessageField(message, field, subdata)
def _convertToBool(obj): if obj not in (0, 1): raise PbDecodeError("Expected a value == " "to 0 or 1, but found a %r" % (type(obj), )) return (obj == 1)
raise PbDecodeError(str(e)) else: for subdata in _getIterator(data): self._deserializeMessage(messageField.add(), subdata) else: if field.type not in MESSAGE_OR_GROUP: if isBool: data = _convertToBool(data) elif isEnum: _ensureValidEnum(field, data) # Because setattr(..., ..., None) for optional fields is # okay, we don't need our own branching here. try: setattr(message, field.name, data) except (TypeError, ValueError), e: raise PbDecodeError(str(e)) else: # On "singular fields", we can just grab a child and set # properties on it. Setting a field on the child will cause # the child's field to exist in the parent. See: # https://code.google.com/apis/protocolbuffers/docs/reference/python-generated.html#fields messageField = getattr(message, field.name) self._deserializeMessage(messageField, data) def _deserializeMessage(self, message, data): """ Mutates C{message} based on C{data}. C{message} is a L{google.protobuf.message.Message}. C{data} is a L{list}. """