Changing Json Data, getting TypeError - python

Edit: Turns out my whole problem was my Json had already been converted to a dictionary previously, without me realising. And I was using json.dumps() instead of .loads() by mistake.
Original Q:I have a piece of Json code I have turned into a dictionary. I am retrieving this Json from a server. When I try access the inner values of the new dictionary to change a value, I get a:
TypeError: string indices must be integers, not str
This is my code:
corner_data = json.dumps(r.json())
print corner_data
corner_data["geometry"]["corners"] = '{"bottom_right": {"y": "575.531616", "x": "690.547363"}, "top_left": {"y": "-146.739075", "x": "-109.105957"}}'

Turn the JSON string into a Python dict using json.loads (not dumps!):*
corner_data = json.loads(r.json())
Modify the data, assigning a Python dict (not a string!):
corner_data['geometry']['corners'] = {'bottom_right': {'y': '575.531616', 'x': '690.547363'}, 'top_left': {'y': '-146.739075', 'x': '-109.105957'}}
Encode it all back into JSON:
print json.dumps(corner_data)
* I'm assuming here that r.json() returns a string. It's entirely possible that r.json() already decodes a JSON string and returns a dict, that depends on what r is. If that's the case, you don't need json.loads here, you can simply omit it.

Related

I can't get a value from a JSON API response in python

So I am struggling with getting a value from a JSON response. Looking in other post I have managed to write this code but when I try to search for the key (character_id) that I want in the dictionary python says that the key doesn't exist. My solution consists in getting the JSON object from the response, converting it into a string with json.dumps() and the converting it into a dictionary with json.loads(). Then I try to get 'character_id' from the dictionary but it doesn't exist. I am guessing it is related with the format of the dictionary but I have little to none experience in python. The code that makes the query and tries to get the values is this: (dataRequest is a fuction that makes the request and return the response from the api)
characterName = sys.argv[1];
response = dataRequest('http://census.daybreakgames.com/s:888/get/ps2:v2/character/?name.first_lower=' + characterName + '&c:show=character_id')
jsonString = json.dumps(response.json())
print(jsonString)
dic = json.loads(jsonString)
print(dic)
if 'character_id' in dic:
print(dic['character_id'])
The output of the code is:
{"character_list": [{"character_id": "5428662532301799649"}], "returned": 1}
{'character_list': [{'character_id': '5428662532301799649'}], 'returned': 1}
Welcome #Prieto! From what I can see, you probably don't need to serialize/de-serialize the JSON -- response.json() returns a python dictionary object already.
The issue is that you are looking for the 'character_id' key at the top-level of the dictionary, when it seems to be embedded inside another dictionary, that is inside a list. Try something like this:
#...omitted code
for char_obj in dic["character_list"]:
if "character_id" in char_obj:
print(char_obj["character_id"])
if your dic is like {"character_list": [{"character_id": "5428662532301799649"}], "returned": 1}
you get the value of character_id by
print(dic['character_list'][0][character_id])
The problem here is that you're trying to access a dictionary where the key is actually character_list.
What you need to do is to access the character_list value and iterate over or filter the character_id you want.
Like this:
print(jsonString)
dic = json.loads(jsonString)
print(dic)
character_information = dic['character_list'][0] # we access the character list and assume it is the first value
print(character_information["character_id"]) # this is your character id
The way I see it, the only hiccup with the code is this :
if 'character_id' in dic:
print(dic['character_id'])
The problem is that, the JSON file actually consists of actually 2 dictionaries , first is the main one, which has two keys, character_list and returned. There is a second sub-dictionary inside the array, which is the value for the key character_list.
So, what your code should actually look like is something like this:
for i in dic["character_list"]:
print(i["character_id"])
On a side-note, it will help to look at JSON file in this way :
{
"character_list": [
{
"character_id": "5428662532301799649"
}
],
"returned": 1
}
,where, elements enclosed in curly-brackets'{}' imply they are in a dictionary, whereas elements enclosed in curly-brackets'[]' imply they are in a list

How can I transform my dict in Json object?

I'm new in Python, and I'm trying to encode in Json an data dict.
My dict is :
data = { ('analogInput', 18) : [('objectName','AI8-Voltage'),
('presentValue',238.3),
('units','Volts')],
('analogInput', 3) : [('objectName','AI3-Pulse'),
('presentValue',100),
('units','Amp')]
}
And when i'm trying to do : foo = json.dumps(data)
I've got this message : Fatal error : keys must be str, int, float, bool or None, not tuple
I'm trying to search answers, but I dont understand how i can do proceed in my case
Thanx you any answers
First of all, not all types can be used for JSON keys.
Keys must be strings, and values must be a valid JSON data type (string, number, object, array, Boolean or null).
For more information, take a look at this.
Now as feasible solution, I recommend you to implement two functions that converts your tuples to string and converts your strings to tuple. A quite simple example is provided below:
import json
data = { ('analogInput', 18) : [('objectName','AI8-Voltage'),
('presentValue',238.3),
('units','Volts')],
('analogInput', 3) : [('objectName','AI3-Pulse'),
('presentValue',100),
('units','Amp')]
}
def tuple_to_str(t):
# It can be implemeneted with more options
return str(t[0])+'_'+str(t[1])
def str_to_tuple(s):
l =s.split('_')
# Your first (second) item is int
l[1] = int(l[1])
return tuple(l)
if __name__=="__main__":
# create a space for a dict of data with string keys
s_data= dict()
for key in data:
s_data[tuple_to_str(key)] = data[key]
x = json.dumps(s_data)
# create a space to load the json with string keys
raw_data = json.loads(x)
final_data = dict()
for key in raw_data:
final_data[str_to_tuple(key)] = raw_data[key]
# Ture
print(final_data)
The error is explicit. In a Python dict, the key can be any hashable type, including a tuple, a frozen set or a frozen dict (but neither a list, nor a set or a dict).
But in a Json object, dictionary keys can only be strings, numbers (int, or float), booleans or the special object None.
Long story short, your input dictionary cannot be directly converted to Json.
Possible workarounds:
use an different serialization tool. For example, pickle can accept any Python type, but is not portable to non Python application. But you could also use a custom serialization format, if you write both the serialization and de-serialization parts
convert the key to a string. At deserialization time, you would just have to convert the string back to a tuple with ast.literal_evel:
js = json.dumps({str(k): v for k,v in data.items()})
giving: {"('analogInput', 18)": [["objectName", "AI8-Voltage"], ["presentValue", 238.3], ["units", "Volts"]], "('analogInput', 3)": [["objectName", "AI3-Pulse"], ["presentValue", 100], ["units", "Amp"]]}
You can load it back with:
data2 = {ast.literal_eval(k): v for k,v in json.loads(js).items()}
giving {('analogInput', 18): [['objectName', 'AI8-Voltage'], ['presentValue', 238.3], ['units', 'Volts']], ('analogInput', 3): [['objectName', 'AI3-Pulse'], ['presentValue', 100], ['units', 'Amp']]}
You can just see that the json transformation has changed the tuples into lists.

Remove 'u' in JSON dictionary

I hope to use the dictionary load by json file. However, each item contains the character 'u'. I need to remove the 'u's.
I tried dumps, but it does not work.
import ast
import json
data= {u'dot',
u'dog',
u'fog',
u'eeee'}
res = eval(json.dumps(data))
print res
I hope to get: {
'dot',
'dog',
'fog,
'eeee'
}
But the error is:
TypeError: set([u'eeee', u'fog', u'dog', u'dot']) is not JSON serializable
The strings that start with u are unicode strings.
In your case, this has nothing to do with the problem:
data= {u'dot',
u'dog',
u'fog',
u'eeee'}
This creates a set and stores the results in the data variable. The json serializer can't handle sets since the json spec makes no mention of them. If you change this to be a list, the serializer can handle the data:
res = set(eval(json.dumps(list(data))))
Here I'm converting the data variable to a list to serialize it, then converting it back to a set to store the result in the res variable.
Alternatively, you can directly ask Python to convert the unicode strings to strings, using something like this:
res = {x.encode("utf-8") for x in data}
print(res)

Yet another Python looping over JSON array

I spent several hours on this, tried everything I found online, pulled some of the hair left on my head...
I have this JSON sent to a Flask webservice I'm writing :
{'jsonArray': '[
{
"nom":"0012345679",
"Start":"2018-08-01",
"Finish":"2018-08-17",
"Statut":"Validee"
},
{
"nom":"0012345679",
"Start":"2018-09-01",
"Finish":"2018-09-10",
"Statut":"Demande envoyée au manager"
},
{
"nom":"0012345681",
"Start":"2018-04-01",
"Finish":"2018-04-08",
"Statut":"Validee"
},
{
"nom":"0012345681",
"Start":"2018-07-01",
"Finish":"2018-07-15",
"Statut":"Validee"
}
]'}
I want to simply loop through the records :
app = Flask(__name__)
#app.route('/graph', methods=['POST'])
def webhook():
if request.method == 'POST':
req_data = request.get_json()
print(req_data) #-> shows JSON that seems to be right
##print(type(req_data['jsonArray']))
#j1 = json.dumps(req_data['jsonArray'])
#j2 = json.loads(req_data['jsonArray'])
#data = json.loads(j1)
#for rec in data:
# print(rec) #-> This seems to consider rec as one of the characters of the whole JSON string, and prints every character one by one
#for key in data:
# value = data[key]
# print("The key and value are ({}) = ({})".format(key, value)) #-> TypeError: string indices must be integers
for record in req_data['jsonArray']:
for attribute, value in rec.items(): #-> Gives error 'str' object has no attribute 'items'
print(attribute, value)
I believe I am lost between JSON object, python dict object, strings, but I don't know what I am missing. I really tried to put the JSON received through json.dumps and json.loads methods, but still nothing. What am I missing ??
I simply want to loop through each record to create another python object that I will feed to a charting library like this :
df = [dict(Task="0012345678", Start='2017-01-01', Finish='2017-02-02', Statut='Complete'),
dict(Task="0012345678", Start='2017-02-15', Finish='2017-03-15', Statut='Incomplete'),
dict(Task="0012345679", Start='2017-01-17', Finish='2017-02-17', Statut='Not Started'),
dict(Task="0012345679", Start='2017-01-17', Finish='2017-02-17', Statut='Complete'),
dict(Task="0012345680", Start='2017-03-10', Finish='2017-03-20', Statut='Not Started'),
dict(Task="0012345680", Start='2017-04-01', Finish='2017-04-20', Statut='Not Started'),
dict(Task="0012345680", Start='2017-05-18', Finish='2017-06-18', Statut='Not Started'),
dict(Task="0012345681", Start='2017-01-14', Finish='2017-03-14', Statut='Complete')]
The whole thing is wrapped in single quotes, meaning it's a string and you need to parse it.
for record in json.loads(req_data['jsonArray']):
Looking at your commented code, you did this:
j1 = json.dumps(req_data['jsonArray'])
data = json.loads(j1)
Using json.dumps on a string is the wrong idea, and moreover json.loads(json.dumps(x)) is just the same as x, so that just got you back where you started, i.e. data was the same thing as req_data['jsonArray'] (a string).
This was the right idea:
j2 = json.loads(req_data['jsonArray'])
but you never used j2.
As you've seen, iterating over a string gives you each character of the string.

TypeError: 'int' object is not iterable, while parsing JSON

I'm working with flask. I have a flask function that receives some posted json and looks like:
#app.route('/index',methods=['POST'])
def index():
import json
json = request.get_json(force=True) # receives request from php
for j in json:
print str(j)
The printed json looks like:
{u'token': u'146bf00b2cb96e6c425c2ab997637', u'a': u'aaa'}
{u'token': u'146bf00b2cb96e6c425c2ab3f7417', u'a': u'bbb'}
{u'token': u'146bf00b2cb96e6c425c2ab3f5692', u'a': u'ccc'}
The number of json records that come in are variable. I need to load the values into a list of dictionaries that looks like:
[{u'token': u'146bf00b2cb96e6c425c2ab997637', u'a': u'aaa'},{u'token': u'146bf00b2cb96e6c425c2ab3f7417', u'a': u'bbb'} ....]
I've tried:
test = [{'a': j[i]['a'], 'token':j[i]['token']} for i in len(json)-1]
However, this is giving me the error listed above. What am I doing wrong?
You don't need to produce a list object because you already have that list. the json variable references it, which is why your for j in json: loop works in the first place.
Your error stems from trying to loop over an integer len(json) - 1:
test = [{'a': j[i]['ad'], 'token':j[i]['token']} for i in len(json)-1]
# ^^^^^^^^^^^
Perhaps you wanted to use range(len(json)) there? Not that there is a need to produce integers here, you could just loop over the json list again to extract what you want:
test = [{'a': entry['a'], 'token': entry['token']} for entry in json]
but this just creates copies of the already existing dictionaries, unless they have more keys you didn't include in your question.

Categories