I have some data coming from a SOAP
API using Suds
which I need to parse in my Python
script. Before I go off and write a parser (ther
You can cast the object to dict()
, but you still get the complex data type used by suds. So here are some helpful functions that I wrote just for the occasion:
def basic_sobject_to_dict(obj):
"""Converts suds object to dict very quickly.
Does not serialize date time or normalize key case.
:param obj: suds object
:return: dict object
"""
if not hasattr(obj, '__keylist__'):
return obj
data = {}
fields = obj.__keylist__
for field in fields:
val = getattr(obj, field)
if isinstance(val, list):
data[field] = []
for item in val:
data[field].append(basic_sobject_to_dict(item))
else:
data[field] = basic_sobject_to_dict(val)
return data
def sobject_to_dict(obj, key_to_lower=False, json_serialize=False):
"""
Converts a suds object to a dict.
:param json_serialize: If set, changes date and time types to iso string.
:param key_to_lower: If set, changes index key name to lower case.
:param obj: suds object
:return: dict object
"""
import datetime
if not hasattr(obj, '__keylist__'):
if json_serialize and isinstance(obj, (datetime.datetime, datetime.time, datetime.date)):
return obj.isoformat()
else:
return obj
data = {}
fields = obj.__keylist__
for field in fields:
val = getattr(obj, field)
if key_to_lower:
field = field.lower()
if isinstance(val, list):
data[field] = []
for item in val:
data[field].append(sobject_to_dict(item, json_serialize=json_serialize))
elif isinstance(val, (datetime.datetime, datetime.time, datetime.date)):
data[field] = val.isoformat()
else:
data[field] = sobject_to_dict(val, json_serialize=json_serialize)
return data
def sobject_to_json(obj, key_to_lower=False):
"""
Converts a suds object to json.
:param obj: suds object
:param key_to_lower: If set, changes index key name to lower case.
:return: json object
"""
import json
data = sobject_to_dict(obj, key_to_lower=key_to_lower, json_serialize=True)
return json.dumps(data)
If there is an easier way, I would love to hear about it.
The checkaayush's answer is not recursive so, it does not consider the nested objects.
Based on aGuegu Answer i did some changes to solve an issue when the suds object has dicts inside lists.
It works!
from suds.sudsobject import asdict
def recursive_asdict(d):
"""Convert Suds object into serializable format."""
out = {}
for k, v in asdict(d).items():
if hasattr(v, '__keylist__'):
out[k] = recursive_asdict(v)
elif isinstance(v, list):
out[k] = []
for item in v:
if hasattr(item, '__keylist__'):
out[k].append(recursive_asdict(item))
elif not isinstance(item, list):
out[k] = item
else:
out[k].append(item)
else:
out[k] = v
return out
There is a class method called dict
in suds.client.Client
class which takes a sudsobject
as input and returns a Python dict
as output. Check it out here: Official Suds Documentation
The resulting snippet becomes as elegant as this:
from suds.client import Client
# Code to obtain your suds_object here...
required_dict = Client.dict(suds_object)
You might also want to check out items
class method (link) in the same class which extracts items from suds_object similar to items
method on dict
.
I was encountering a similar problem and had to read a suds response.
Suds response will be returned as a tuple consisting of objects.
len(response) will show you the number of objects contained in the suds response tuple.
In order to access the first object we need to give response[0]
.
In IDLE if you type >>>print response[0]
followed by a period '.' symbol you will get a popup showing the various objects that can be accessed from this level.
Example: if you type response[0]
. it will bring a popup and show the Balance object so the command would now become response[0].Balance
.
You can follow the same approach to get the list of objects under the subsequent levels
Found one solution:
from suds.sudsobject import asdict
def recursive_asdict(d):
"""Convert Suds object into serializable format."""
out = {}
for k, v in asdict(d).iteritems():
if hasattr(v, '__keylist__'):
out[k] = recursive_asdict(v)
elif isinstance(v, list):
out[k] = []
for item in v:
if hasattr(item, '__keylist__'):
out[k].append(recursive_asdict(item))
else:
out[k].append(item)
else:
out[k] = v
return out
def suds_to_json(data):
return json.dumps(recursive_asdict(data))
If subs are just nested dict and list, it should work.
The right answer, as is often the case, is in the docs. The bits in (brackets) are objects which can contain other objects or types.
In this case we have an ArrayOfBalance
object which contains a list of Balance
types, each of which has the attributes of Amount
and Currency
.
These can all be referred to using .
notation so the following one-liner does the trick.
balance = {item.Currency: item.Amount for item in response.Balance}