Json dump for key, pair in Python - python

I have below file which is the result of a json dump.
"fdd6a102-359c-4527-8469-4ef01a9c0076": "[\n {\n \"resource_status\": \"CREATE_COMPLETE\", \n \"resource_name\": \"i4_instance_internal_port\", \n \"resource_type\": \"OS::Neutron::Port\", \n \"physical_resource_id\": \"5db1d412-9a43-45c7-b72d-0dbe4eb16497\", \n \"updated_time\": \"2017-07-14T09:00:44\"\n }, \n {\n \"resource_status\": \"CREATE_COMPLETE\", \n \"resource_name\": \"i3_instance\", \n \"resource_type\": \"OS::Nova::Server\", \n \"physical_resource_id\": \"50375d90-5b57-412e-afe3-fdddefbd2f41\", \n \"updated_time\": \"2017-07-14T09:00:44\"\n }, \n {\n \"resource_status\": \"CREATE_COMPLETE\", \n \"resource_name\": \"i3_v1_instance_volume\", \n \"resource_type\": \"OS::Cinder::Volume\", \n \"physical_resource_id\": \"6750dc3d-e682-4a0c-a177-83a7252822fb\", \n \"updated_time\": \"2017-07-14T09:00:44\"\n }\n]\n"
This file is messed up I think. It is not in the right format. I researched on how to dump in json
def pp_another_json(myDict):
import io
try:
to_unicode = unicode
except NameError:
to_unicode = str
# Write JSON file
with io.open('data.json', 'w', encoding='utf8') as outfile:
str_ = json.dumps(myDict,
indent=4, sort_keys=True,
ensure_ascii=False)
outfile.write(to_unicode(str_))
class getstackList():
def getStackID(self):
stacks = get_objects('stacks')
myDict = {}
for stack in stacks:
try:
myDict[stack.id] = subprocess.check_output(["openstack", "stack", "resource", "list", stack.id, "-f", "json"])
pp_another_json(myDict)
except subprocess.CalledProcessError as e:
print("Error")
The output of openstack stack resource list -f json comes in below format
[
{
"resource_status": "CREATE_COMPLETE",
"resource_name": "i4_instance_internal_port",
"resource_type": "OS::Neutron::Port",
"physical_resource_id": "5db1d412-9a43-45c7-b72d-0dbe4eb16497",
"updated_time": "2017-07-14T09:00:44"
},
{
"resource_status": "CREATE_COMPLETE",
"resource_name": "i3_instance",
"resource_type": "OS::Nova::Server",
"physical_resource_id": "50375d90-5b57-412e-afe3-fdddefbd2f41",
"updated_time": "2017-07-14T09:00:44"
},
]
Now my problems
The json dump file doesn't really look like json to me. How can I get it to be in proper format
The json dump file is a big one. so I have key as the ID and the value is the list inside which there is another dictionary.(I think so) How do I fetch data in such scenario?
I need to check for example if 'resource_type' is OS::Cinder::Volume, how will I get it or else if I need to get the value of resource_type, how will I get it?
It will be helpful if someone can explain me my json file. Or if not, please direct me to the links that could help me understand nested dictionaries
Edited : To fetch the value I did below and is giving me
ValueError: too many values to unpack
with open('data.json') as data_file:
data_loaded = json.load(data_file)
for key, value in data_loaded:
print(data_loaded[key][0]['resource_status'])
data.json is below

Your JSON dump can be viewed as a simple dictionary in python. So for your first part you can use the following :
import json
#Assuming 'mydict' contains the json dump
with open('out.json', 'w') as outfile:
json.dump(mydict, outfile)
Now coming to the second part, suppose for the first element (fdd6a102-359c-4527-8469-4ef01a9c0076") in your example you need to access the 'resource-status' key of the first element in the list, you simply need to use the following:
myjson["fdd6a102-359c-4527-8469-4ef01a9c0076"][0]['resource-status']
More information can be found here.
For your final part, you view this answer on nested JSON.

Related

How to delete everything inside an object in a json file but keep the object?

I want to delete everything in the object "name" in the given json file example but keep the the object, in simple words I want to clear the object.
{
"names": [
{
"player": "Player_Name",
"TB:": "12389",
"BW:": "596",
"SW:": "28",
"CQ:": "20"
}
]
}
I used tried this code:
with open('players.json', 'w') as w:
with open('players.json', 'r') as r:
for line in r:
element = json.loads(line.strip())
if 'names' in element:
del element['names']
w.write(json.dumps(element))
but it just clears the whole json file
sorry for my bad english
The problem is that you open the same file twice - for reading and for writing simultaneously. Also a JSON cannot be parsed line by line, only as a whole.
import json
# 1. read
with open('players.json', 'r') as r:
data = json.load(r)
# 2. modify
# (you might want to check if data is a dict)
data['names'] = []
# 3. write
with open('players.json', 'w') as w:
data = json.dump(data, w)

Adding nested dictionaries into an already existing JSON file with dictionary

I've recently started to learn some python.
After finishing all the learnpython.org tutorials I'm trying something on my own (So you know my knowledge level).
I want to build a small script that lets you build a DnD character and save it in a file. The idea was to use JSON (Since this was included in the learnpython tutorials) and put in dictionaries along the lines of:
data = { playerName ; {"Character Name" : characterName, "Character Class" : characterClass...ect.}}
I was hoping that it is possible to add new dics into the JSON file inside that original data dic, So the dictionary is a list of playerName's that have the character dics under them.
Not only did I fail to get it exactly like this, I also fail at just adding following dictionaries without making the file unreadable. Here is my code, since it isn't very long:
import json
def dataCollection():
print("Please write your character name:")
characterName = input()
print("%s, a good name! \nNow tell me your race:" % characterName)
characterRace = input()
print("And what about the class?")
characterClass = input()
print("Ok so we have; \nName = %s \nRace = %s \nClass = %s \nPlease tell me the player name now:" % (characterName, characterRace, characterClass))
playerName = input()
print("Nice to meet you %s. \nI will now save your choices..." % playerName)
localData = { playerName :
{"Character Name" : characterName,
"Character Class" : characterClass,
"Character Race" : characterRace}}
with open("%s_data_file.json" % playerName, "a") as write_file:
json.dump(localData, write_file)
dataCollection()
with open("data_file.json", "r") as read_file:
data = json.load(read_file)
# different .json name here since I'm trying around with different files
print(data)
Edit: It might also be possible that JSON is not the "right" thing to use for my idea. If you have any alternative ideas for storing that information (Besides straight txt file), feel free to suggest them!
i made little modification, i try to read the file for init the data json, if it fail i init the data.
import json
def createPlayer():
print("Please write your character name : ")
characterName = input()
print("%s, a good name! \nNow tell me your race : " % characterName)
characterRace = input()
print("Nice to meet you %s. \nI will now save your choices..." % characterName)
try :
with open('data_file.json') as json_file:
data = json.load(json_file)
except :
data = {}
data['player'] = []
data['player'].append({
'name': characterName,
'race': characterRace,
})
with open("data_file.json", "w+") as write_file:
json.dump(data, write_file)
createPlayer()
with open("data_file.json", "r") as read_file:
data = json.load(read_file)
print(data)
I think that the way you think of a dictionnary might not be exactly what it is.
A dictionary is a data structure that can holds many key-value pairs.
Here the key to your dictionary would be the player's name and the value would be the dictionary that holds the character's name, class and race.
So a json file that holds a dictionary cannot be appended to because a json file can only hold 1 json object.
{ 'playerName': {...character\'s attributes...}}
If you were to open the file and append a json object (like you do at the end of dataCollection) then your file would be like this
{ 'playerName':
{...characters attributes...}
}
{ 'playerName2':
{...characters attributes...}
}
And when reading the file json will stop when the first json object it finds will end. So it won't load the 2nd dictionary.
If you want to add something to the dictionary inside your json file, you need to load the json file to access the dictionary and then add your new key-value pair and then dump this new dictionary. Which will result in the following json file:
{ 'playerName':
{...characters attributes...},
'playerName2':
{...characters attributes...}
}
I hope it's kinda clear.

Why JSON can not be read if written with indentation in PYTHON 3.8

With indentation:
a_dict = ({"name": "kevin", "id":100001 })
with open('test.json',"a+") as f:
json.dump(a_dict, f, indent=4) # Indent makes it more readable
f.write("\n")
print("done")
Output as below, won't be able to read, says json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes:
{
"name": "kevin",
"id": 100001
}
{
"name": "kevin",
"id": 100001
}
Without indentation:
a_dict = ({"name": "kevin", "id":100001 })
with open('test.json',"a+") as f:
json.dump(a_dict, f) # Indent makes it more readable
f.write("\n")
print("done")
Output that can be read:
{"name": "kevin", "id": 100001}
{"name": "kevin", "id": 100001}
{"name": "kevin", "id": 100001}
{"name": "kevin", "id": 100001}
Decoding:
p_list = []
with open('test.json') as f:
for json_obj in f:
test_dict = json.loads(json_obj)
p_list.append(test_dict)
# print(test_dict)
for emp in p_list:
print(emp['name'])
Looks like you're trying to use the JSONL / JSON Lines format. The predicate for this format is that each object, or whichever JSON entity, is wholly represented in a single line of the file. So you can't have it be JSONL and indented/prettified at the same time.
When you do:
with open('test.json') as f:
for json_obj in f:
...
each json_obj is just one line of the file, not the JSON object read-in till the end of that object.
If you want to do it that way, you'll need to write your own JSON Decoder that reads in more lines until it's found the end-delimiter and a valid JSON entity. Same goes for writing the file - you'd need to write your own JSON Encoder.
The closest thing to being able to do JSON Lines & Pretty'fied is jq command line tool. And since it's not a Python package, in order to read and write data, use subprocess.run() with capture_output=True.
You can find questions related to this tool on StackOverflow with the tag jq.
Edit: If you are certain that you will only be writing JSON objects to the file the same way always, you can setup the read to start at a line which starts with { without any spaces/indentation before it and continue reading until you reach a line with } without any spaces/indentation before it.
A rough idea:
with open('test.json') as f:
parts = []
in_obj = False
for some_text in f:
if some_text == '{' and not in_obj:
in_obj = True
parts.append('{')
elif in_obj:
parts.append(some_text)
if some_text == '}':
in_obj = False
# put this in a try-except block
json_obj = json.loads('\n'.join(parts))
yield json_obj # or return
parts = [] # reset
elif not some_text.startswith(' ' * 4):
print('error') # in an object but wrong indent
# the check above should actually include checking more than
# just the starting 4 spaces since it could be nested further
else:
print('error') # not in an object and not end delimeter
You'll need to modify that to read multiple objects and be an actual parser.
Also, as noted by #ewen-lbh below, files in this format should have the .jsonl extension. If it's .json you're implying that it holds a single valid loadable json entity.

How can i insert new json object to existing json file (in the middle of object)

filejson.json
{"Fiksi":[
{
"judul":"fiksi1",
"pengarang":"pengarang1",
"file":"namafiksi1.txt"
},
{
"judul":"fiksi2",
"pengarang":"pengarang2",
"file":"namafiksi2.txt"
}
],
"Non-Fiksi":[
{
"judul":"nonfiksi1",
"penulis":"penulis1",
"file":"namanonfiksi1.txt"
},
{
"judul":"nonfiksi2",
"penulis":"penulis2",
"file":"namanonfiksi2.txt"
}
]
I want to insert new object on tag "Fiksi". so the item can insert in the middle of file json.
The object like this :
item = {"judul":"fiksi3", "pengarang":"pengarang3","file":"namafiksi3.txt"}
my code now :
config = json.loads(open('filejson.json').read())
with open('filejson.json','a') as f:
data = f["Fiksi"].append(item)
json.dumps(data)
its not working
Step1: Read data
config = json.loads(open('filejson.json').read())
Step2: Update data (in python object)
config["Fiksi"].append(item)
Step3: Write all data (not append) back to file
with open('filejson.json','w') as f:
f.write(json.dumps(config))
On a side note, you can use json.load and json.dump instead for json.loads and json.dumps when dealing with files, so it will be
with open('filejson.json', 'r') as f:
config = json.load(f)
config["Fiksi"].append(item)
with open('filejson.json','w') as f:
json.dump(config, f)
The best way is to work with python objects:
import json
Load your file with json.load
Insert in the loaded dict
Dump to a file with json.dump
Just add:
f.write(json.dumps(data))

Python read JSON file and modify

Hi I am trying to take the data from a json file and insert and id then perform POST REST.
my file data.json has:
{
'name':'myname'
}
and I would like to add an id so that the json data looks like:
{
'id': 134,
'name': 'myname'
}
So I tried:
import json
f = open("data.json","r")
data = f.read()
jsonObj = json.loads(data)
I can't get to load the json format file.
What should I do so that I can convert the json file into json object and add another id value.
Set item using data['id'] = ....
import json
with open('data.json', 'r+') as f:
data = json.load(f)
data['id'] = 134 # <--- add `id` value.
f.seek(0) # <--- should reset file position to the beginning.
json.dump(data, f, indent=4)
f.truncate() # remove remaining part
falsetru's solution is nice, but has a little bug:
Suppose original 'id' length was larger than 5 characters. When we then dump with the new 'id' (134 with only 3 characters) the length of the string being written from position 0 in file is shorter than the original length. Extra chars (such as '}') left in file from the original content.
I solved that by replacing the original file.
import json
import os
filename = 'data.json'
with open(filename, 'r') as f:
data = json.load(f)
data['id'] = 134 # <--- add `id` value.
os.remove(filename)
with open(filename, 'w') as f:
json.dump(data, f, indent=4)
I would like to present a modified version of Vadim's solution. It helps to deal with asynchronous requests to write/modify json file. I know it wasn't a part of the original question but might be helpful for others.
In case of asynchronous file modification os.remove(filename) will raise FileNotFoundError if requests emerge frequently. To overcome this problem you can create temporary file with modified content and then rename it simultaneously replacing old version. This solution works fine both for synchronous and asynchronous cases.
import os, json, uuid
filename = 'data.json'
with open(filename, 'r') as f:
data = json.load(f)
data['id'] = 134 # <--- add `id` value.
# add, remove, modify content
# create randomly named temporary file to avoid
# interference with other thread/asynchronous request
tempfile = os.path.join(os.path.dirname(filename), str(uuid.uuid4()))
with open(tempfile, 'w') as f:
json.dump(data, f, indent=4)
# rename temporary file replacing old file
os.rename(tempfile, filename)
There is really quite a number of ways to do this and all of the above are in one way or another valid approaches... Let me add a straightforward proposition. So assuming your current existing json file looks is this....
{
"name":"myname"
}
And you want to bring in this new json content (adding key "id")
{
"id": "134",
"name": "myname"
}
My approach has always been to keep the code extremely readable with easily traceable logic. So first, we read the entire existing json file into memory, assuming you are very well aware of your json's existing key(s).
import json
# first, get the absolute path to json file
PATH_TO_JSON = 'data.json' # assuming same directory (but you can work your magic here with os.)
# read existing json to memory. you do this to preserve whatever existing data.
with open(PATH_TO_JSON,'r') as jsonfile:
json_content = json.load(jsonfile) # this is now in memory! you can use it outside 'open'
Next, we use the 'with open()' syntax again, with the 'w' option. 'w' is a write mode which lets us edit and write new information to the file. Here s the catch that works for us ::: any existing json with the same target write name will be erased automatically.
So what we can do now, is simply write to the same filename with the new data
# add the id key-value pair (rmbr that it already has the "name" key value)
json_content["id"] = "134"
with open(PATH_TO_JSON,'w') as jsonfile:
json.dump(json_content, jsonfile, indent=4) # you decide the indentation level
And there you go!
data.json should be good to go for an good old POST request
try this script:
with open("data.json") as f:
data = json.load(f)
data["id"] = 134
json.dump(data, open("data.json", "w"), indent = 4)
the result is:
{
"name":"mynamme",
"id":134
}
Just the arrangement is different, You can solve the problem by converting the "data" type to a list, then arranging it as you wish, then returning it and saving the file, like that:
index_add = 0
with open("data.json") as f:
data = json.load(f)
data_li = [[k, v] for k, v in data.items()]
data_li.insert(index_add, ["id", 134])
data = {data_li[i][0]:data_li[i][1] for i in range(0, len(data_li))}
json.dump(data, open("data.json", "w"), indent = 4)
the result is:
{
"id":134,
"name":"myname"
}
you can add if condition in order not to repeat the key, just change it, like that:
index_add = 0
n_k = "id"
n_v = 134
with open("data.json") as f:
data = json.load(f)
if n_k in data:
data[n_k] = n_v
else:
data_li = [[k, v] for k, v in data.items()]
data_li.insert(index_add, [n_k, n_v])
data = {data_li[i][0]:data_li[i][1] for i in range(0, len(data_li))}
json.dump(data, open("data.json", "w"), indent = 4)
This implementation should suffice:
with open(jsonfile, 'r') as file:
data = json.load(file)
data[id] = value
with open(jsonfile, 'w') as file:
json.dump(data, file)
using context manager for the opening of the jsonfile.
data holds the updated object and dumped into the overwritten jsonfile in 'w' mode.
Not exactly your solution but might help some people solving this issue with keys.
I have list of files in folder, and i need to make Jason out of it with keys.
After many hours of trying the solution is simple.
Solution:
async def return_file_names():
dir_list = os.listdir("./tmp/")
json_dict = {"responseObj":[{"Key": dir_list.index(value),"Value": value} for value in dir_list]}
print(json_dict)
return(json_dict)
Response look like this:
{
"responseObj": [
{
"Key": 0,
"Value": "bottom_mask.GBS"
},
{
"Key": 1,
"Value": "bottom_copper.GBL"
},
{
"Key": 2,
"Value": "copper.GTL"
},
{
"Key": 3,
"Value": "soldermask.GTS"
},
{
"Key": 4,
"Value": "ncdrill.DRD"
},
{
"Key": 5,
"Value": "silkscreen.GTO"
}
]
}

Categories