googleads / googleads-python-lib

The Python client library for Google's Ads APIs
Apache License 2.0
681 stars 974 forks source link

Network Service has is not JSON serializable issue #359

Open RRSchweitzer opened 5 years ago

RRSchweitzer commented 5 years ago

I went from googleads 10 to the newest version of ad manager and now a simple get of all networks associated with a service email account does not work anymore. I get a serialization error with the response. This was not an issue before upgrading. If I downgrade again everything goes back to normal. Is there something I need to do? I've even printed the entire object I'm attempting the json.dumps on and if I copy that into a new script and place it into a json.dumps function it works so there doesn't appear to be anything wrong with the list I'm passing in. This also make it very hard to debug this issue. Error:

File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default    raise TypeError(repr(o) + " is not JSON serializable")

TypeError: {
    'id': 604966L,
    'displayName': None,
    'networkCode': '203086286',
    'propertyCode': 'ca-pub-3065783271784989',
    'timeZone': 'Europe/Amsterdam',
    'currencyCode': 'EUR',
    'secondaryCurrencyCodes': [],
    'effectiveRootAdUnitId': '202086406',
    'isTest': False
} is not JSON serializable
import services
import json
import flask
from datetime import datetime, timedelta
from pytz import timezone
import pytz
from time import gmtime, strftime
from suds.sudsobject import asdict
NETWORK = ""
dfp = services.ad_manager

def recursive_asdict(data):
   result = {}
   for key, value in asdict(data).iteritems():
       if hasattr(value, '__keylist__'):
           result[key] = recursive_asdict(value)
       elif isinstance(value, list):
           result[key] = []
           for item in value:
               if hasattr(item, '__keylist__'):
                   result[key].append(recursive_asdict(item))
               else:
                   result[key].append(item)
       else:
           result[key] = value
   return result

def suds_to_json(data):
   result = []
   if(isinstance(data, list)):
       for item in data:
           if hasattr(item, '__keylist__'):
               result.append(recursive_asdict(item))
           else:
               result.append(item)
       return json.dumps(result)
   return json.dumps(recursive_asdict(data))

def getNetworks():
   return suds_to_json(services.NetworkService.getAllNetworks())

def connect(networkId, method, params=None):
   global NETWORK
   if (NETWORK != networkId):
       services.connectToNetwork(networkId)
       NETWORK = networkId  
    try:
       if(params):
           return method(params)
       return method()
   except Exception,e:
       print e
       if hasattr(e, 'fault'):
           return suds_to_json(e.fault), 400
       else:
           return e, 500

services.py

import credentials
from googleads import ad_manager, oauth2

oauth2_client = oauth2.GoogleServiceAccountClient(credentials.KEY_FILE, oauth2.GetAPIScope('ad_manager'))
dfp_client = ad_manager.AdManagerClient(oauth2_client, credentials.APPLICATION_NAME)
NetworkService = dfp_client.GetService('NetworkService', version=credentials.API_VERSION)

def connectToNetwork(networkId):
    global ReportService
    client.network_code = networkId;
    ReportService = client.GetDataDownloader(version=credentials.API_VERSION)
RRSchweitzer commented 5 years ago

I discovered what the main issue is that the objects within the result variable are Zeep objects and they are not serializable. The problem resolved by importing Zeep and using its helper functions to serialize the results. I believe this is a workaround though.

RRSchweitzer commented 5 years ago

I think the suds zeep might also be causing an issue with checking results. Currently, in all the example scripts there is an if 'results' in response:..if no results then it exits but currently this is the result that comes back...

{ 'totalResultSetSize': 26L, 'startIndex': 27500L, 'results': [] }

The results are always there and therefore will need to check the length of the array.