Protobuf: Python: Converting JSON to Protobuf, AttributeError: 'property' object has no attribute 'SetInParent'

Created on 20 Apr 2017  路  4Comments  路  Source: protocolbuffers/protobuf

I'm trying to convert a JSON message to proto3 using Python, but I keep getting an error about AttributeError: 'property' object has no attribute 'SetInParent'. This error comes from the json_format object.

My JSON code is:

{
  "id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
  "timestamp": "1970-01-01T00:00:00.000Z",
  "lang": "en",
  "result": {
    "source": "agent",
    "resolvedQuery": "Hello example",
    "action": "",
    "actionIncomplete": false,
    "parameters": {
      "Intent": "value"
    },
    "contexts": [],
    "metadata": {
      "intentId": "b2a8e424-77f8-4855-b798-3a7504adf352",
      "webhookUsed": "false",
      "webhookForSlotFillingUsed": "false",
      "intentName": "demo_speech"
    },
    "fulfillment": {
      "speech": "Speech text",
      "messages": [
        {
          "type": 0,
          "speech": "Speech text"
        }
      ]
    },
    "score": 1.0
  },
  "status": {
    "code": 200,
    "errorType": "success"
  },
  "sessionId": "id"
}

My protobuf:

syntax = "proto3";
package apiaiproto;

option optimize_for = SPEED;

import "google/protobuf/any.proto";

message QueryResponse {
    string id = 1;
    string timestamp = 2;
    string lang = 3;
    RequestResult result = 4;
    Status status = 5;
    string sessionId = 6;
}

message ResponseContext {
    string name = 1;
    google.protobuf.Any parameters = 2;
    uint32 lifespan = 3;
}

message Fulfillment {
    string speech = 1;
    repeated Message messges = 2;
}

message Metadata {
    string intentId = 1;
    string webhookUsed = 2;
    string webhookForSlotFillingUsed = 3;
    string intentName = 4;
}

// refer to https://docs.api.ai/docs/status-object
message Status {
    uint32 code = 1;
    string errorType = 2;
    string errorId = 3;
    string errorDetails = 4;
}

message Message {
    uint32 type = 1;
    string speech = 2;
    string imageUrl = 3;
    string title = 4;
    string subtitle = 5;
    repeated string replies = 7;
}

message RequestResult {
    string source = 1;
    string resolvedQuery = 2;
    string action = 3;
    bool actionIncomplete = 4;
    google.protobuf.Any parameters = 5;
    repeated Context contexts = 6;
    Fulfillment fulfillment = 7;
    double score = 8;
    Metadata metadata = 9;
}

After compiling the Python source, I tried the below and got an error.

from google.protobuf import json_format

from proto import apiai_pb2

response = '{
  "id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
  "timestamp": "1970-01-01T00:00:00.000Z",
  "lang": "en",
  "result": {
    "source": "agent",
    "resolvedQuery": "Hello example",
    "action": "",
    "actionIncomplete": false,
    "parameters": {
      "Intent": "value"
    },
    "contexts": [],
    "metadata": {
      "intentId": "b2a8e424-77f8-4855-b798-3a7504adf352",
      "webhookUsed": "false",
      "webhookForSlotFillingUsed": "false",
      "intentName": "demo_speech"
    },
    "fulfillment": {
      "speech": "Speech text",
      "messages": [
        {
          "type": 0,
          "speech": "Speech text"
        }
      ]
    },
    "score": 1.0
  },
  "status": {
    "code": 200,
    "errorType": "success"
  },
  "sessionId": "id"
}'

# create a message from JSON string
json_format.Parse(response, apiai_pb2.QueryResponse, ignore_unknown_fields=False)
"""
This throws the error mentioned. 
"""

I have tried excluding nested messages (RequestResult and Status), and the message gets parsed correctly, It looks like nested JSON objects are the cause because the below works, and I'm able to parse messages if they aren't nested.

import json

# extract `status` from JSON, and parse it
json_format.Parse(json.loads(json.dumps(response).get('status')), apiai_pb2.Status, ignore_unknown_fields=False)

Most helpful comment

The second argument to json_format.Parse() is a Message instance, not a type. It populates the passed-in instance with the data from the JSON and returns the same.

You'll want to do this:
parsed_pb = json_format.Parse(response, apiai_pb2.QueryResponse(), ignore_unknown_fields=False)

Or this (given some preexisting QueryResponse instance):
json_format.Parse(response, query_response_instance, ignore_unknown_fields=False)

All 4 comments

The second argument to json_format.Parse() is a Message instance, not a type. It populates the passed-in instance with the data from the JSON and returns the same.

You'll want to do this:
parsed_pb = json_format.Parse(response, apiai_pb2.QueryResponse(), ignore_unknown_fields=False)

Or this (given some preexisting QueryResponse instance):
json_format.Parse(response, query_response_instance, ignore_unknown_fields=False)

Thanks @jbmorgan, fixes my issue

Thanks @jbmorgan that saved my day

Hello,

This is my json_parse
json_object = {"features": response1, "relevance": response2, "response": response3, "status": 200}
parsed_pb = json_format.Parse(json.dumps(json_object), melon_pb2.QueryResponse(), ignore_unknown_fields=False)

I am sending this back as response of an flask rest API, will that be efficient than json sending.

Also how to calculate size of parsed_db object.

I am using pympler and sys but they are always giving 80 bytes as output, is that correct?

Please help!

Was this page helpful?
0 / 5 - 0 ratings