json.loads function not giving python dictionary - json

I am trying to convert the below mentioned json string to python dictionary. I am using python 3's json package for the same. Here is the code that I am using :
a = "[{'id': 35, 'name': 'Comedy'}, {'id': 18, 'name': 'Drama'}, {'id': 10751, 'name': 'Family'}, {'id': 10749, 'name': 'Romance'}]"
b = json.loads(json.dumps(a))
print(type(b))
And the output that I am getting from the above code is:
<class 'str'>
I saw the similar questions asked in stackoverflow, but the solutions presented for those questions do not apply to my case.

The json string that you are trying to convert is not properly formatted. Also, you need to only call json.loads to convert string into dict or list.
The updated code would look like:
import json
a = '[{"id": 35, "name": "Comedy"}, {"id": 18, "name": "Drama"}, {"id": 10751, "name": "Family"}, {"id": 10749, "name": "Romance"}]'
b = json.loads(a)
print(type(b))
Hope this explains why you are not getting the expected results.

JSON Array is enclosed in [ ] while JSON object is enclosed in { }
The string in a is a json array so you can change that into a list only.
Your key and value should be enclosed with double quotes, that's the requirement to use json library of python.
b = json.loads(a) will give a list of dictionary objects.
To get further dictionary of dictionary you need to associate a key with each individual dictionary.
d = dict()
ind = 0
for data in b:
d[ind] = data
ind+=1
Now the output that you get will be
{0: {'id': 35, 'name': 'Comedy'}, 1: {'id': 18, 'name': 'Drama'}, 2: {'id': 10751, 'name': 'Family'}, 3: {'id': 10749, 'name': 'Romance'}}
which is a dictionary of dictionary.
Thank you

Related

How can I add feature information from one json into geoJson using id/codarea as the identifier?

The following steps show where you can download the files to reproduce this question. How can I add municipality information from one json object into the other using id/codarea as the identifier.
Requesting geojson
import folium
import os
import requests
url = 'https://servicodados.ibge.gov.br/api/v2/malhas/?resolucao=5&formato=application/vnd.geo+json&qualidade=4'
meshes_mun = requests.get(url, headers=headers).json()
File structure snippet:
{'type': 'Feature',
'properties': {'codarea': '2303600',
'centroide': [-36.722055140733, -6.158308569735204]},
'geometry': {'type': 'Polygon',
'coordinates': [[[-36.6532, -6.1118],
[-36.6828, -6.1277],
[-36.7005, -6.1453],
.....
In the following you can find string names and ids that I want to link with the meshes_mun above.
The names and ids I need to link with is the higher level: 'id': 2303600, 'nome': 'Catarina', so don't need to add the other features, but they could be added if it's ok.
# url to request information of all municipalities (contains the id number)
mun_url = 'https://servicodados.ibge.gov.br/api/v1/localidades/municipios'
cities_json = requests.get(mun_url, headers=headers).json()
File structure snippet:
{'id': 2303600,
'nome': 'Catarina',
'microrregiao': {'id': 23020,
'nome': 'Sertão de Inhamuns',
'mesorregiao': {'id': 2304,
'nome': 'Sertões Cearenses',
'UF': {'id': 23,
'sigla': 'CE',
'nome': 'Ceará',
'regiao': {'id': 2, 'sigla': 'NE', 'nome': 'Nordeste'}}}}},
How can I add feature information from one json into geoJson using id/codarea as the identifier?
Can be done something like this
import requests
url = "https://servicodados.ibge.gov.br/api/v2/malhas/?resolucao=5&formato=application/vnd.geo+json&qualidade=4"
meshes_mun = requests.get(url).json()
mun_url = "https://servicodados.ibge.gov.br/api/v1/localidades/municipios"
cities_json = requests.get(mun_url).json()
for mun in meshes_mun["features"]:
codarea = int(mun["properties"]["codarea"])
matched_city = [city for city in cities_json if city["id"] == codarea][0]
mun["properties"]["nome"] = matched_city["nome"]

How do I access the value from a dictionary in a list in a dictionary?

for example this is the data:
data = {'number': 3, 'message': 'success', 'people': [{'craft': 'ISS', 'name': 'Chris Cassidy'}, {'craft': 'ISS', 'name': 'Anatoly Ivanishin'}, {'craft': 'ISS', 'name': 'Ivan Vagner'}]}
how do I print only the names of the people in this case?
required output:
('Chris Cassidy', 'Anatoly Ivanishin', 'Ivan Vagner')
I can't wrap my head around this, please help. :)
Try:
names = []
for person in data["people"]:
names.append(person["name"])
names will then have your desired list.

Why does dask.bag.read_text(filename).map(json.loads) return a list?

I need to read several json.gz files using Dask. I am trying to achieve this by using dask.bag.read_text(filename).map(json.loads), but the output is a nested list (the files contain lists of dictionaries), whereas I would like to get a just a list of dictionaries.
I have included a small example that reproduces my problem, below.
import json
import gzip
import dask.bag as db
dict_list = [{'id': 123, 'name': 'lemurt', 'indices': [1,10]}, {'id': 345, 'name': 'katin', 'indices': [2,11]}]
filename = './test.json.gz'
# Write json
with gzip.open(filename, 'wt') as write_file:
json.dump(dict_list , write_file)
# Read json
with gzip.open(filename, "r") as read_file:
data = json.load(read_file)
# Read json with Dask
data_dask = db.read_text(filename).map(json.loads).compute()
print(data)
print(data_dask)
I would like to get the first output:
[{'id': 123, 'name': 'lemurt', 'indices': [1, 10]}, {'id': 345, 'name': 'katin', 'indices': [2, 11]}]
But instead I get the second one:
[[{'id': 123, 'name': 'lemurt', 'indices': [1, 10]}, {'id': 345, 'name': 'katin', 'indices': [2, 11]}]]
The read_text function returns a bag, where each element is a line of text. So you have a list of strings. Then, you parse each of those lines of text with json.loads, so each of those lines of text becomes a list again. So you have a list of lists.
In your case you might use map_partitions, and a function that expects a list of a single line of text
b = db.read_text("*.json.gz").map(lambda L: json.loads(L[0]))
Following the comment by #MRocklin, I ended up solving my problem by changing the way I was writing the json.gz files.
Instead of
with gzip.open(filename, 'wt') as write_file:
json.dump(dict_list , write_file)
I used
with gzip.open(filename, 'wt') as write_file:
for dd in dict_list:
json.dump(dd , write_file)
write_file.write("\n")
and kept reading the files as
db.read_text(filename).map(json.loads)

Creating JSON data from string and using json.dumps

I am trying to create JSON data to pass to InfluxDB. I create it using strings but I get errors. What am I doing wrong. I am using json.dumps as has been suggested in various posts.
Here is basic Python code:
json_body = "[{'points':["
json_body += "['appx', 1, 10, 0]"
json_body += "], 'name': 'WS1', 'columns': ['RName', 'RIn', 'SIn', 'OIn']}]"
print("Write points: {0}".format(json_body))
client.write_points(json.dumps(json_body))
The output I get is
Write points: [{'points':[['appx', 1, 10, 0]], 'name': 'WS1', 'columns': ['RName', 'RIn', 'SIn', 'OIn']}]
Traceback (most recent call last):
line 127, in main
client.write_points(json.dumps(json_body))
File "/usr/local/lib/python2.7/dist-packages/influxdb/client.py", line 173, in write_points
return self.write_points_with_precision(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/influxdb/client.py", line 197, in write_points_with_precision
status_code=200
File "/usr/local/lib/python2.7/dist-packages/influxdb/client.py", line 127, in request
raise error
influxdb.client.InfluxDBClientError
I have tried with double quotes too but get the same error. This is stub code (to minimize the solution), I realize in the example the points list contains just one list object but in reality it contains multiple. I am generating the JSON code reading through outputs of various API calls.
json_body = '[{\"points\":['
json_body += '[\"appx\", 1, 10, 0]'
json_body += '], \"name\": \"WS1\", \"columns\": [\"RName\", \"RIn\", \"SIn\", \"OIn\"]}]'
print("Write points: {0}".format(json_body))
client.write_points(json.dumps(json_body))
I understand if I used the below things would work:
json_body = [{ "points": [["appx", 1, 10, 0]], "name": "WS1", "columns": ["Rname", "RIn", "SIn", "OIn"]}]
You don't need to create JSON manually. Just pass an appropriate Python structure into write_points function. Try something like that:
data = [{'points':[['appx', 1, 10, 0]],
'name': 'WS1',
'columns': ['RName', 'RIn', 'SIn', 'OIn']}]
client.write_points(data)
Please visit JSON.org for proper JSON structure. I can see several errors with your self-generated JSON:
The outer-most item can be an unordered object, enclosed by curly braces {}, or an ordered array, enclosed by brackets []. Don't use both. Since your data is structured like a dict, the curly braces are appropriate.
All strings need to be enclosed in double quotes, not single. "This is valid JSON". 'This is not valid'.
Your 'points' value array is surrounded by double brackets, which is unnecessary. Only use a single set.
Please check out the documentation of the json module for details on how to use it. Basically, you can feed json.dumps() your Python data structure, and it will output it as valid JSON.
In [1]: my_data = {'points': ["appx", 1, 10, 0], 'name': "WS1", 'columns': ["RName", "RIn", "SIn", "OIn"]}
In [2]: my_data
Out[2]: {'points': ['appx', 1, 10, 0], 'name': 'WS1', 'columns': ['RName', 'RIn', 'SIn', 'OIn']}
In [3]: import json
In [4]: json.dumps(my_data)
Out[4]: '{"points": ["appx", 1, 10, 0], "name": "WS1", "columns": ["RName", "RIn", "SIn", "OIn"]}'
You'll notice the value of using a Python data structure first: because it's Python, you don't need to worry about single vs. double quotes, json.dumps() will automatically convert them. However, building a string with embedded single quotes leads to this:
In [5]: op_json = "[{'points':[['appx', 1, 10, 0]], 'name': 'WS1', 'columns': ['RName', 'RIn', 'SIn', 'OIn']}]"
In [6]: json.dumps(op_json)
Out[6]: '"[{\'points\':[[\'appx\', 1, 10, 0]], \'name\': \'WS1\', \'columns\': [\'RName\', \'RIn\', \'SIn\', \'OIn\']}]"'
since you fed the string to json.dumps(), not the data structure.
So next time, don't attempt to build JSON yourself, rely on the dedicated module to do it.

how to use a jsonfiy object in assertions?

I am trying to unit test some code, and want to assert that the jsonify output of the code is correct. here is what I have so far.
def test_get_ticket(self):
with self.app.test_request_context('/?main_id=14522&user_id=82'):
methodOutput = brain_get_ticket.get_ticket({'main_id': {1: 0}, 'status': {'Closed': 0},
'available': {'False': 0}}, "main_id, status, available",
['main_id', 'status', 'available'])
correct_return_output = json.dumps(dict(
to_be_working_on_last_id=0,
to_be_working_on_id=6,
information={'status': {'Closed': 1}, 'available': {'False': 1}, 'main_id': {1: 1}}
))
self.assertEquals(json.loads(methodOutput.data()), correct_return_output, "output was: " + str(methodOutput) + " it should be: " + str(correct_return_output))
the output i'm getting is :
self.assertEquals(json.loads(methodOutput.data()), correct_return_output)
TypeError: 'str' object is not callable
any suggestions????
Solved:
the main problem was that I was using data as if it was a method, not a descriptor, like Martijn said. Also changing the correct_return_output to a dictionary instead of a jsonify object to compare to the actual method output worked. THANKS!
Response.data is a descriptor and does not need to be called; you are trying to call the returned JSON string here.
Your better bet is to decode that JSON response; dictionaries are unordered and you should not count on what order the resulting JSON data is listed in. You already do so, but then you should compare that against a dictionary, not a new JSON string!
def test_get_ticket(self):
with self.app.test_request_context('/?main_id=14522&user_id=82'):
methodOutput = brain_get_ticket.get_ticket(
{'main_id': {1: 0}, 'status': {'Closed': 0},
'available': {'False': 0}},
"main_id, status, available", ['main_id', 'status', 'available'])
correct_return_output = dict(
to_be_working_on_last_id=0,
to_be_working_on_id=6,
information={'status': {'Closed': 1},
'available': {'False': 1},
'main_id': {1: 1}})
self.assertEquals(
json.loads(methodOutput.data),
correct_return_output,
"output was: {!r}, it should be {!r}".format(
methodOutput.data, correct_return_output))