def decode_message(message_type, encoded_message):
  """Merge JSON structure to Message instance.

  Args:
    message_type: Message to decode data to.
    encoded_message: JSON encoded version of message.

  Returns:
    Decoded instance of message_type.

  Raises:
    ValueError: If encoded_message is not valid JSON.
    messages.ValidationError if merged message is not initialized.
  """
  if not encoded_message.strip():
    return message_type()

  dictionary = json.loads(encoded_message)

  def find_variant(value):
    """Find the messages.Variant type that describes this value.

    Args:
      value: The value whose variant type is being determined.

    Returns:
      The messages.Variant value that best describes value's type, or None if
      it's a type we don't know how to handle.
    """
    if isinstance(value, (int, long)):
      return messages.Variant.INT64
    elif isinstance(value, float):
      return messages.Variant.DOUBLE
    elif isinstance(value, basestring):
      return messages.Variant.STRING
    elif isinstance(value, (list, tuple)):
      # Find the most specific variant that covers all elements.
      variant_priority = [None, messages.Variant.INT64, messages.Variant.DOUBLE,
                          messages.Variant.STRING]
      chosen_priority = 0
      for v in value:
        variant = find_variant(v)
        try:
          priority = variant_priority.index(variant)
        except IndexError:
          priority = -1
        if priority > chosen_priority:
          chosen_priority = priority
      return variant_priority[chosen_priority]
    # Unrecognized type.
    return None

  def decode_dictionary(message_type, dictionary):
    """Merge dictionary in to message.

    Args:
      message: Message to merge dictionary in to.
      dictionary: Dictionary to extract information from.  Dictionary
        is as parsed from JSON.  Nested objects will also be dictionaries.
    """
    message = message_type()
    for key, value in dictionary.iteritems():
      if value is None:
        message.reset(key)
        continue

      try:
        field = message.field_by_name(key)
      except KeyError:
        # Save unknown values.
        variant = find_variant(value)
        if variant:
          message.set_unrecognized_field(key, value, variant)
        else:
          logging.warning('No variant found for unrecognized field: %s', key)
        continue

      # Normalize values in to a list.
      if isinstance(value, list):
        if not value:
          continue
      else:
        value = [value]

      valid_value = []
      for item in value:
        if isinstance(field, messages.EnumField):
          try:
            item = field.type(item)
          except TypeError:
            raise messages.DecodeError('Invalid enum value "%s"' % value[0])
        elif isinstance(field, messages.BytesField):
          try:
            item = base64.b64decode(item)
          except TypeError, err:
            raise messages.DecodeError('Base64 decoding error: %s' % err)
        elif isinstance(field, message_types.DateTimeField):
          try:
            item = util.decode_datetime(item)
          except ValueError, err:
            raise messages.DecodeError(err)
        elif isinstance(field, messages.MessageField):
          item = decode_dictionary(field.type, item)
        elif (isinstance(field, messages.FloatField) and
              isinstance(item, (int, long, basestring))):
          try:
            item = float(item)
          except:
            pass
        elif (isinstance(field, messages.IntegerField) and
              isinstance(item, basestring)):
          try:
            item = int(item)
          except:
            pass
        valid_value.append(item)

      if field.repeated:
        existing_value = getattr(message, field.name)
        setattr(message, field.name, valid_value)
      else:
        setattr(message, field.name, valid_value[-1])
    return message

  message = decode_dictionary(message_type, dictionary)
  message.check_initialized()
  return message
dataset/ETHPy150Open AppScale/appscale/AppServer/lib/protorpc/protorpc/protojson.py/decode_message/original