fneron fneron - 5 months ago 13
JSON Question

Assign array to key dictionary in python

I'm not guru in python. I don't get why I can't assign an array of values to a key for this dictionnary with this def.

This is how I use the sdk definition.

return_keys_list = []
return_keys_list.append('id')
return_keys_list.append('transaction.amount')
redirect.returnKeys(return_keys_list)


This is the specific definition in the sdk I use
https://github.com/OptimalPayments/Python_SDK/blob/63e1ae662a4447bd65c907563eec9effc602dd74/src/PythonNetBanxSDK/HostedPayment/Redirect.py

'''
Property Return Keys
'''
def returnKeys(self, return_keys):
self.__dict__['returnKeys'] = return_keys


From what I could debug, the problems comes when converting the array into json to be sent.The loop finds the array and try to convert the elements inside (strings), but since by default the loop consider each given parameter as array, the returnKeys parameter is skipped...

'''
Serializing object
@param: Dictionary Object
@return: Serialized data
'''
def serialize(self, obj):
return (json.dumps(self.to_dictionary(obj)))

'''
Convert object to a dictionary
@param: POJO Object
@return: Dictionary Object
'''
def to_dictionary(self, obj):
obj_dict = dict()
for key in obj.__dict__.keys():
try:
if(type(obj.__dict__[key]) is list):
content = []
for count in range(0, obj.__dict__[key].__len__()):
content.append(
self.to_dictionary(obj.__dict__[key][count]))
obj_dict[key] = content
elif(isinstance(obj.__dict__[key], DomainObject)):
obj_dict[key] = self.to_dictionary(obj.__dict__[key])
else:
obj_dict[key] = obj.__dict__[key]
except KeyError:
pass
except AttributeError:
pass
return (obj_dict)


I have no problem assigning a key to one value, but when I try assigning an array to a key, it doesn't work and it just ignore this key from the json output.

Answer

I've reproduced this:

import json

class S:

    def serialize(self, obj):
        return (json.dumps(self.to_dictionary(obj)))

    def to_dictionary(self, obj):
        obj_dict = dict()
        for key in obj.__dict__.keys():
            try:
                if(type(obj.__dict__[key]) is list):
                    content = []
                    for count in range(0, obj.__dict__[key].__len__()):
                        content.append(self.to_dictionary(obj.__dict__[key][count]))
                    obj_dict[key] = content
                # elif(isinstance(obj.__dict__[key], DomainObject)):
                #    obj_dict[key] = self.to_dictionary(obj.__dict__[key])
                else:
                    obj_dict[key] = obj.__dict__[key]
            except KeyError:
                pass
            except AttributeError:
                pass
        return (obj_dict)


class A:
    def __init__(self):
        self.a = "1234"                                                         
        self.b = (1, 2, 3, 4)                                                   
        self.c = [1, 2, 3, 4]                                                   
        self.d = { 1: 2, 3: 4}               

print S().serialize(A())

Output:

{"a": "1234", "b": [1, 2, 3, 4], "d": {"1": 2, "3": 4}}

The problem is that when the code recurses into to_dictionary() with the items in the list, the code always expects that it is recursing with a object that contains a __dict__. But neither a string (nor an int) contain a __dict__. (Which I see you've stated similarly in the question.)

I would file an issue on the github referring to this question.

Other than patching their code, your only option is to create a class that has the items you want. It appears they do not support a string or int except as a value in a __dict__.

You could use a dict as a list:

class ReturnList:
    def __init__(self):
        self.list = { 1: "Item1", 2: "Item2" }

redirect.returnKeys(ReturnList())

Addendum:

Wait! Why did the tuple case work?? I think you could do:

redirect.returnKeys((1,2,3,4))

Oh, I see why it works. It's a bug. They specifically handle list but not tuple, and it doesn't recurse for tuple types. Since the tuple contains directly json-able types, it just converts it to a json list. If your tuple contained a class or other more complex (non-json) objects, it would fail.

Comments