How to get rid of extra curly braces in JSON? - python

I'm basically creating a contact book, and I want to do it storing data on JSON to practice it. I have sort a code that allows it from a dictionary, but the problem is that when I rerun the script, another dictionary is appended into the existing one, creating a couple of extra braces which throws the error "End of file expected."
This is the code:
import json
new_contacts = {}
def contacts():
while True:
name = input("Contact's name: ")
email = input("Email: ")
number = input("Phone number: ")
new_contacts[name] = {"email": email, "number": number}
"""cursor.execute(
'INSERT INTO contacts VALUES (?, ?, ?)',
(name, email, number)
)"""
restart_or_not = input("Continue? y/n ").lower()
if restart_or_not == "y":
print(new_contacts)
continue
else:
with open('contact_book.json', 'a') as file:
json.dump(new_contacts, file, indent=4)
break
contacts()
And this is a sample of a JSON that comes out from it:
{
"d": {
"email": "e",
"number": "3"
},
"h": {
"email": "y",
"number": "6"
},
"f": {
"email": "r",
"number": "3"
},
"n": {
"email": "j",
"number": "9"
}
}{
"g": {
"email": "j",
"number": "0"
}
}
The first four entries don't create any problem because they are appended in the same run, but if I quit the program and rerun it (example "g") then the new dictionary creates the conflict. Any tips?

One way of doing it, is before adding to the file, you delete the last closing bracket } and before dumping, you cast your dict into a string and remove the first bracket using this your_string[1:].
The other way which I coded for you, is you load the json into a variable, add the new inputs and then re dump it into the file
import json
from os import path # it helps to check if file exists
new_contacts = {}
def contacts():
while True:
name = input("Contact's name: ")
email = input("Email: ")
number = input("Phone number: ")
new_contacts[name] = {"email": email, "number": number}
"""cursor.execute(
'INSERT INTO contacts VALUES (?, ?, ?)',
(name, email, number)
)"""
restart_or_not = input("Continue? y/n ").lower()
if restart_or_not == "y":
print(new_contacts)
continue
else:
# if the file doesn't exist, write an empty json object into it
# which will make it easier later to load data from
if not path.exists('contact_book.json'):
with open('contact_book.json', 'w+') as file:
json.dump({}, file)
# This loads the data into the variable dict called loaded_data
with open('contact_book.json', 'r') as file:
loaded_data = json.load(file)
for k, v in new_contacts.items():
loaded_data[k] = v
# redumps your data into the json file
with open('contact_book.json', 'w') as file:
json.dump(loaded_data, file, indent=4)
break
contacts()

Just updated a bit of the else part of your code. It checks whether a file exists or not. If it exists, the contents of the file is read and updated and then dumped into the file. If it doesn't exist, your old code will be executing.
if os.stat("contact_book.json").st_size != 0:
with open('contact_book.json', 'r+') as file:
contents = json.loads(file.read())
contents.update(new_contacts)
file.seek(0)
json.dump(contents, file, indent=4)
else:
with open('contact_book.json', 'a') as file:
json.dump(new_contacts, file, indent=4)
break
Honestly, not an efficient solution. But this should be able to invoke an idea.

Related

python dictionary update without overwriting

I am learning python, and I have two json files. The data structure in these two json files are different structures.
I start by importing both of the json files. I want to choose a course from the courses dict, and then add it to a specific education in the educations dict.
What I want to solve is via user input choose a key from the first dict, and then within a while loop, so I can add choose a key from the second dict to be added to the dict chosen from the first dict.
I am able to add the dict from the second dict to the one first as a sub dict as I want to, but with the update method it overwrites all previous values.
I have used the dict.update() method so not to overwrite previous values. I then want to write back the updated dict back to the first json file.
My code works partially, I am able to add a course to a educations, but it overwrites all previous courses I chose to add to a specific education.
This is the content of the first json file:
{
"itsak22": {
"edcuationId": "itsak22",
"edcuation_name": "cybersecurityspecialist"
},
"feu22": {
"edcuationId": "feu22",
"edcuation_name": "frontendutvecklare"
}
}
This is the content of the second json file:
{
"sql": {
"courseId": "itsql",
"course_name": "sql",
"credits": 35
},
"python": {
"courseId": "itpyt",
"course_name": "python",
"credits": 30
},
"agile": {
"courseId": "itagl",
"course_name": "agile",
"credits": 20
}
}
And this is my python code:
import json
# Load the first JSON file of dictionaries
with open('edcuations1.json') as f:
first_dicts = json.load(f)
# Load the second JSON file of dictionaries
with open('courses1.json') as f:
second_dicts = json.load(f)
# Print the keys from both the first and second JSON files
print("All educations:", first_dicts.keys())
print("All courses:", second_dicts.keys())
# Ask for input on which dictionary to add to which
first_key = input("Which education would you like to choose to add courses to? (Enter 'q' to quit): ")
while True:
second_key = input("Which course would you like to add to education? (Enter 'q' to quit)")
if second_key == 'q':
break
# Create a sub-dictionary named "courses" in the specific dictionary of the first file
if "courses" not in first_dicts[first_key]:
first_dicts[first_key]["courses"] = {}
first_dicts[first_key]["courses"].update(second_dicts[second_key])
#first_dicts = {**first_dicts, **second_dicts}
#first_dicts.update({'courses': second_dicts})
# Update the first JSON file with the new dictionaries
with open('edcuations1.json', 'w') as f:
json.dump(first_dicts, f, indent=4)
Here is my approach:
import json
# Load the first JSON file of dictionaries
with open("educations1.json") as f:
educations = json.load(f)
# Load the second JSON file of dictionaries
with open("courses1.json") as f:
courses = json.load(f)
# Print the keys from both the first and second JSON files
print("All educations:", educations.keys())
print("All courses:", courses.keys())
# Ask for input on which dictionary to add to which
education_key = input(
"Which education would you like to choose to add courses to? (Enter 'q' to quit): "
)
education_courses = educations[education_key].setdefault("courses", {})
while True:
course_key = input(
"Which course would you like to add to education? (Enter 'q' to quit): "
)
if course_key == "q":
break
education_courses[course_key] = courses[course_key]
# Update the first JSON file with the new dictionaries
with open("educations1.json", "w") as stream:
json.dump(educations, stream, indent=4)
A few notes
I fixed the typos: edcuations1.json -> educations1.json
Instead of generic names such as first_dicts, first_keys, ... I use more descriptive names
How it works
The heart of my solution is on this line:
education_courses = educations[education_key].setdefault("courses", {})
Which is the equivalent of:
if "courses" not in educations[education_key]:
educations[education_key]["courses"] = {}
education_courses = educations[education_key]["courses"]
The setdefault method basically assign a value (an empty dictionary in this case) to a dictionary if the key ("courses" in this case) is absent.
I'm not entirely sure how your desired result should look like but I think your dictionary courses should be a list and not a dictionary.
Then you can do
if "courses" not in first_dicts[first_key]:
first_dicts[first_key]["courses"] = []
first_dicts[first_key]["courses"].append (second_dicts[second_key])
And your result looks like this if you add all courses to itsak22
{
"itsak22": {
"edcuationId": "itsak22",
"edcuation_name": "cybersecurityspecialist",
"courses": [
{
"courseId": "itsql",
"course_name": "sql",
"credits": 35
},
{
"courseId": "itpyt",
"course_name": "python",
"credits": 30
},
{
"courseId": "itagl",
"course_name": "agile",
"credits": 20
}
]
},
"feu22": {
"edcuationId": "feu22",
"edcuation_name": "frontendutvecklare"
}
}

How do i append at a json file at the end of the list with python

So i want to put some json strings like this
[{"username": "username", "key": "key"}, {"username": "username", "key": "key"}, ...]
i tried json.dump and json.dumps but it doesn't worked for me, please help me
this is the code that i written for now:
import json
username = input('Username to put in the keys file: ')
key = input('Key to put in the keys file: ')
uak = {"username": username, "key": key}
with open('keys.json', 'r') as r:
data = json.load(r)
with open('keys.json', 'w') as w:
json.dump(data, w)
Your keys.json file's content initially must be equal to [] that matchs an empty json array to append your objects at runtime, then you have to add your {"username": username, "key": key} json object to your data list with the append method like below:
#keys.json is initialized with []
import json
username = input('Username to put in the keys file: ')
key = input('Key to put in the keys file: ')
uak = {"username": username, "key": key}
with open('keys.json', 'r') as r:
data = json.load(r)
with open('keys.json', 'w') as w:
data.append(uak)
json.dump(data, w)

Handling keys inside a key from .json file

I am trying to print an specific key from a JSON file without success.
.json file is:
{
"testing": [
{
"_name": "teste",
"_profile_telphone": "212331233",
"_age": "21"
}
]
}
the function I'm using is:
def load(self):
filename = self.profile_entry.get()
if filename == "":
msg = "Insert a profile name"
messagebox.showinfo("Profile name is empty", msg)
self.profile_entry.focus()
else:
with open('profile_'+filename+'.json', 'r') as outfile:
data = json.load(outfile)
print(data[filename])
outfile.close()
with print(data[filename]) I can print entire
{
"_name": "teste",
"_profile_telphone": "212331233",
"_age": "21"
}
But how can I print only name or age for example?
data is a list of JSONs - you have a json array there, in order to parse it you can do it with a for statement
for element in data[filename]:
print(element[‘_name’])
print(element[‘_profile_telphone’])
print(element[‘_age’])

JSON file not reading

import json
import io
username = input('Enter your username ') #Input
password = input('Now enter your password ') #Input
usernamelow = username.lower()
username input converts to lowercase
auth = {
"users": usernamelow,
"pass": password
}
the JSON string that is writ to the JSON file
dump = json.dumps(auth) #Gathers data
print (dump) #Debug print
with open('auth.json', 'a') as outfile:
for line in outfile:
json.dump(auth, outfile, indent=4)
(Dumps AUTH)
adds data to the JSON file ^
with open('auth.json', 'r') as f:
data = json.load(f)
Basically this is a school project I'm working on and when I append to the file more than once it gives me an extra data error. This is the JSON that appears when the script is ran:
{
"pass": "testpass",
"users": "testuser"
}{
"users": "testinguser",
"pass": "testingpass"
}
I appear to get this error:
ValueError: Extra data: line 4 column 2 - line 7 column 2 (char 52 -
110)
Okay so the following error tells us something:-
ValueError: Extra data
The data you're trying to load is not properly formatted in JSON. The correct JSON formatting would be:-
[{
"pass": "testpass",
"users": "testuser"
}, {
"users": "testinguser",
"pass": "testingpass"
}]
A better practice would be to input all the data once in a list of dicts, and then you can dump it into the file as a whole:-
with open('auth.json', 'a') as outfile:
json.dump(auth_list, outfile, indent=4)
The error might be the missing comma between the entries
Another way is, first to collect all existing data from your file in a list (of dictionaries) and then append the new input. this might be usefull for checks of duplicates
import json
import os
auth_list = []
file_name = 'auth.json'
if os.path.isfile(file_name):
with open(file_name, 'r') as f:
auth_list = json.load(f)
print(auth_list)
username = input('Enter your username ')
password = input('Now enter your password ')
usernamelow = username.lower()
auth = {
"users": usernamelow,
"pass": password
}
auth_list.append(auth)
with open(file_name, 'w') as outfile:
json.dump(auth_list, outfile)
This might be also a usefull ressource https://realpython.com/python-json/

indent is broken after saving back updated json dict to file

I have a nested dictionary with many items in a json file:
{
"Create Code For Animals": {
"mammals": {
"dog": {
"color": "brown",
"name": "John",
"legs": "four",
"tail": "yes"
},
"cat": {
"color": "blue",
"name": "Johnny",
"legs": "four",
"tail": "yes"
},
"donkey": {
"color": "grey",
"name": "Mickey",
"legs": "four",
"tail": "yes"
}
I want to replace the name in each one of the animals, then save it back to the file, AND keep the indent as it was (as shown).
I'm using the following 2 methods for loading and dumping the original and updated dictionary.
All is working well (for changing the value and saving it back to the file) except the indent (format) of the lines is ruined after saving the file and the file is saved as one long line (with '\n' shown after the updated value).
I've tried using 'pickle' (as seen in one of the posts here), but this didn't work, made a mess of all the data in the file.
def loadJson(self, jsonFilename):
with open(FILE_PATH + '\\' + jsonFilename, 'r') as f:
return json.load(f)
def writeJson(self, jsonFilename, jsonDict):
with open(FILE_PATH + '\\' + jsonFilename, 'w') as f:
return json.dump(jsonDict, f)
Any help will do.
json.dumps and dump have a parameter called indent
If ``indent`` is a non-negative integer, then JSON array elements and
object members will be pretty-printed with that indent level. An indent
level of 0 will only insert newlines. ``None`` is the most compact
representation. Since the default item separator is ``', '``, the
output might include trailing whitespace when ``indent`` is specified.
You can use ``separators=(',', ': ')`` to avoid this
Something like this would do:
json.dump(jsonDict,f,indent=4)

Categories