Adding and saving to list in external json file - python

I'm very new to Python and I'm struggling when it comes to saving the data that the user has entered to a json file when quitting the application. Also every time I run my code all the data inside the json file is wiped. When I enter the input to save and exit I get this error code:
Traceback (most recent call last):
File "C:\Users\User\Downloads\sit_resources\sit_resources\sit_admin_application.py", line 86, in <module>
main_menu()
File "C:\Users\User\Downloads\sit_resources\sit_resources\sit_admin_application.py", line 23, in main_menu
save()
File "C:\Users\User\Downloads\sit_resources\sit_resources\sit_admin_application.py", line 82, in save
patients_file.write(finallist)
io.UnsupportedOperation: not writable
Here is my code below:
import json
patients_file = open("patients.json", "r")
loaded_patients = json.load(patients_file)
def main_menu():
'''Function docstring documentation here'''
print("\nSIT Data Entry Menu")
print("==========================")
print("1: Print Patients' List\n2: Add Patient\n3: Delete Patient\n4: Exit")
print("==========================")
input1 = input("Enter your menu selection:")
if input1 == "1":
patients_list()
elif input1 == "2":
add_patient()
elif input1 == "3":
remove_patient()
elif input1 == "4":
save()
else:
print ("Please enter a valid input")
main_menu()
def patients_list():
print("\nSIT current patients:\n")
loaded_patients.sort(key=str.casefold)
for number, item in enumerate(loaded_patients, start=1):
print(number, item)
print("\nTotal number of registered patients is", len(loaded_patients))
main_menu()
def add_patient():
newpatient = input("\nEnter new Patient -> Lastname Firstname:")
print ("Do the details you have entered look correct? y/n")
confirm = input()
if confirm == "y":
loaded_patients.append(newpatient)
print ("Patient successfully added to list")
main_menu()
elif confirm == "n":
print ("Patient import cancelled")
add_patient()
else:
print ("Please enter a valid input")
add_patient()
def remove_patient():
print ("Which of the following patients would you like to remove?")
loaded_patients.sort(key=str.casefold)
for number, item in enumerate(loaded_patients, start=1):
print(number, item)
try:
removepatient = int(input("\nEnter the number of the patient you would like to remove"))
print ("Does the patient number you have entered look correct? y/n")
delconfirm = input()
if delconfirm == "y":
try:
removepatient = (removepatient - 1)
loaded_patients.pop(removepatient)
print ("Patient was successfully removed from the list")
main_menu()
except IndexError:
print("Please enter a valid input")
remove_patient()
elif delconfirm == "n":
print ("Deletion cancelled")
remove_patient()
else:
print ("Please enter a valid input")
remove_patient()
except ValueError:
print ("Please enter a valid input")
remove_patient()
def save():
open("patients.json", "w")
finallist = json.dumps(loaded_patients)
patients_file.write(finallist)
print("Patient List successfully saved")
quit()
main_menu()
I store the json file in the same directory and all it contains is a list:
["Soreback Leigh", "Neckache Annette", "Sorefoot Jo", "Kaputknee Matt", "Brokentoe Susan", "Tornligament Alex"]
If anyone could help me out and let me know what I'm doing wrong or any simpler method I could use, it would be greatly appreciated.
Thanks

Your code has several issues, including the one you're asking about.
The main thing is the overall structure: your code keeps calling functions from functions, never really returning - that can work for a very long time, but in the end it will fail, and it's not the correct way to go about this.
Take for example your main_menu() - once an option is selected, you call the function matching it, and when the work there is done, you call main_menu() again. However, a better way to do the same:
def main_menu():
choice = ''
while choice != '4':
print('some options, 4 being "save and quit"')
if choice == 1:
patients_list()
...
# no if choice == 4: save() here, we'll save at the end
save()
This way, the menu will keep getting printed when you return to it, but every function that is executed, is allowed to return and then the loop restarts, unless option 4 was entered. And since you can allow the functions to return, no need to call main_menu() at the end of them.
Your save() function has some issues: it doesn't need quit() any more, but you also didn't do anything with the file you opened. A nice way to do this in Python is to use a 'context manager', which boils down to using with, like this:
def save():
with open("patients.json", "w") as patients_file:
finallist = json.dumps(loaded_patients)
patients_file.write(finallist)
That's assuming your loaded_patients always contains all the current patients of course. Given that's what it is for, you should consider just calling it patients.
Your file only contains a list, because a list is what you are creating in those functions and a list is a valid content for a json file. If you expected a dictionary, you should construct one in the rest of the code, but from your example it's unclear what exactly you would expect that dictionary to look like.

The conventional way to load and save json:
with open('patients.json', 'r') as f:
loaded_patients = json.load(f)
with open('patients.json', 'w') as f:
json.dump(loaded_patients, f)

You are trying to write to patients_file, which you opened in read-only mode.

Related

I keep getting traceback and str callback errors after so much troubleshooting and I can't seem to fix it. Python contacts book

i have saved the dictionary in a separeate document with all the correct syntax called directory.txt. The code is for a contacts book/directory using dictionaries. I'm not sure wheter im supposed to define functions before or after calling them but i've tried both and it still doesnt seem to work.
file = open("directory.txt","r+")
contacts = file.read()
def new():
print("Please enter the name of the new contact.")
name = input()
print("Please enter the number of the new contact.")
num = input()
contacts.update({name:num})
print("Contact has successfully been added.")
def view():
for keys, values in contacts():
print("\n*************************************************")
print("Name:",keys)
print("Number:",values)
print("*************************************************\n")
def edit():
for keys, values in contacts():
print("\n*************************************************")
print("Name:",keys)
print("Number:",values)
print("*************************************************\n")
print("Type the name of the contact you would like to edit.")
global name_two
name_two = input()
print("If you would like to edit the number, type 'number'.\nIf you would like to edit the name, type 'name'.\nIf you would like to delete this contact, type 'delete'.")
edit = input().lower()
if edit == "number":
num_edit()
elif edit == "name":
name_edit()
elif edit == "delete":
delete()
def num_edit():
print("What would you like to change the number to?")
num_two = input()
contacts[name_two] = num_two
print("Contact successfully changed.")
def name_edit():
num_save = contacts[name_two]
del contacts[name_two]
print("Enter the new name for the contact.")
name_new = input()
contacts.update({name_new:num_save})
print("Contact successfully changed.")
def delete():
del contacts[name_two]
print("Contact successfully deleted.")
print("Welcome to the Contacts Book.")
print("*****************************\n")
print("If you would like to make a new contact, type 'new'.\nIf you would like to view your contacts, type 'view'.\n If you would like to edit your contacts, type 'edit'.\nIf you would like to exit, type 'exit'")
mode = input().lower()
if mode == "new":
new()
elif mode == "view":
view()
elif mode == "edit":
edit()
else:
print("Goodbye.")
Here is the error message when i type 'view' as the first input:
File "c:\Users\brain\Downloads\contacts.py", line 56, in <module>
view()
File "c:\Users\brain\Downloads\contacts.py", line 11, in view
for keys, values in contacts():
TypeError: 'str' object is not callable
I think you have some variable named str in your code and that caused this problem. This is called shadowing the built in functions, you can try to find that variable with a search in your project file and change it to some other name and should solve it.
I believe you just have an unnecessary set of parenthesis after contacts (it's a var not a function as far as I can see), so just remove those and you should be good. EDIT: gimix reply is far more accurate than what I wrote here

Python dictionary becomes empty as soon as the function, which added items to it, finishes execution

I am trying to write a menu in which option 1 would add a key:value pair to a dictionary and option 2 would run a threading module using the items from the dictionary. Key is a message from the user input and Value is a number of seconds, from the user input, that a thread should pause for, before displaying the message.
Threading itself is irrelevant right now though. What I'm struggling with is the fact that when I use the function for option 1, it adds the key:value pairs to the dictionary (called messages_and_times) successfully. But as soon as the function is finished the dictionary becomes empty again, as can be seen from the function for option 2, which accesses it.
At the bottom you can see my code. I've added the following lines in order to check what's in the dictionary at each step:
print(dict(messages_and_times))
if not messages_and_times:
print("This dictionary is empty.")
else:
print("This dictionary contains items.")
It doesn't seem to work correctly either however. First of all it prints "This dictionary contains items." whether the printed dictionary looks empty or not. Second of all the following part of my code (clear() is used for clearing the terminal display):
def create_dictionary():
clear()
answer = input(
"Would you like to add another message? (yes/no)").lower()
if answer == "yes":
option_1()
elif answer == "no":
clear()
print("You will now be returned to the main menu.")
print(dict(messages_and_times))
does print a dictionary containing items if I chose to add them. But if I add the line
print(dict(messages_and_times))
to the main_menu() itself, the above mentioned create_dictionary() function prints an empty dictionary instead. Just this one print() statement in the main_menu() affects whether create_dictionary() shows a dictionary with items in it or not.
Could someone please help me understand how to design a code in which the dictionary retains the items created by one function, so that they can be accessed by other functions?
Thank you in advance for your time and assistance,
import os
clear = lambda: os.system('cls')
def main_menu():
list_of_messages = []
list_of_times = []
messages_and_times = zip(list_of_messages, list_of_times)
def option_1():
clear()
list_of_messages.append(
input("Please type in a message you would like to add to the list:"))
clear()
list_of_times.append(
input("Please type in the time of delay for this message:"))
def create_dictionary():
clear()
answer = input(
"Would you like to add another message? (yes/no)").lower()
if answer == "yes":
option_1()
elif answer == "no":
clear()
print("You will now be returned to the main menu.")
print(dict(messages_and_times))
if not messages_and_times:
print("This dictionary is empty.")
else:
print("This dictionary contains items.")
time.sleep(1.5)
main_menu()
else:
clear()
print("Please answer yes or no.")
time.sleep(1.5)
create_dictionary()
create_dictionary()
def option_2():
clear()
print(dict(messages_and_times))
if not messages_and_times:
print("This dictionary is empty.")
else:
print("This dictionary contains items.")
time.sleep(5)
main_menu()
clear()
selection = 0
while selection == 0:
print(("-" * 15) + "MAIN MENU" + ("-" * 15) + "\n")
print("1: Input a message and a corresponding time of delay before its display.")
print("2: Print your customized list of messages.")
print("3: Generate a list of random messages with random delays.\n")
selection = int(input(
"Please select one of the options, by typing in the corresponding number:"))
if selection == 1:
option_1()
elif selection == 2:
option_2()
elif selection == 3:
clear()
print("You've selected the third option.")
else:
clear()
print("Please select from options 1 - 3.\n")
time.sleep(1.5)
main_menu()

errors with Elif expected indented block

I'm trying to create a menu for my application, the menu has 4 options and each of these options should return with the correct information when the user has entered the chosen value. i keep getting an error with the Elif statements.
I am a newbie so please understand where am coming from.
much appreciation.
when i indent the while ans: i will receive an error says invalid syntax after indenting the elif ans==2.
elif ans==2 <--- this error keeps saying indention block error or syntex invalid when i indent it.
def print_menu(self,car):
print ("1.Search by platenumber")
print ("2.Search by price ")
print ("3.Delete 3")
print ("4.Exit 4")
loop=True
while loop:
print_menu()
ans==input("Please choose from the list")
if ans==1:
print("These are the cars within this platenumber")
return platenumber_
while ans:
if ans==2:
elif ans==2:
print("These are the prices of the cars")
return price_
elif ans==3:
print("Delete the cars ")
return delete_
elif ans==4:
return Exit_
loop=False
else:
raw_input("please choose a correct option")
You have a while loop without a body. Generally speaking, if there is an indentation error message and the error is not on the line mentioned, it's something closely above it.
loop=True
while loop:
print_menu()
ans = int(input("Please choose from the list"))
if ans==1:
print("These are the cars within this platenumber")
# return some valid information about plate numbers
elif ans==2:
print("These are the prices of the cars")
# return some valid information about pricing
elif ans==3:
print("Delete the cars ")
# Perform car deletion action and return
elif ans==4:
# I am assuming this is the exit option? in which case
# return without doing anything
else:
# In this case they have not chosen a valid option. Send
# A message to the user, and do nothing. The while loop will run again.
print("please choose a correct option")
Also, your code is a bit confusing to me. It looks like you're going to return car_ no matter what, which means your loop will only execute once. Also, = is assignment and == is equality. Be careful.

Program Loops Very Quickly and Indefinitely? Can't Figure Out Why

I'm working on a Tweet Manager program in python for my programming class. For the assignment, I'm supposed to create a Tweet class that stores the author of a tweet, the tweet itself, and the time the tweet was created. Then, I'm supposed to create a Twitter program that gives users a menu of options to choose from.
When I try to run my Twitter program, it opens without syntax errors, but prints the Menu over and over and over again really rapidly without stopping. I can't figure out what in my code is causing this problem.
Here is my Twitter code:
import Tweet
import pickle
def main():
try:
load_file = open('tweets.dat', 'rb')
tweets = pickle.load('tweets.dat')
load_file.close()
except:
tweet_list = []
while (True):
choice = display_menu()
#Make a Tweet
if (choice == 1):
tweet_author = input("\nWhat is your name? ")
tweet_text = input("What would you like to tweet? ")
print()
if len(tweet_text) > 140:
print("Tweets can only be 140 characters!\n")
else:
print(tweet_author, ", your Tweet has been saved.")
age = 0
tweets = tweet.Tweet(tweet_author, tweet_text)
tweet_list.append(tweets)
try:
output_file = open('tweets.dat', 'wb')
pickle.dump(tweets, output_file)
output_file.close()
except:
print("Your tweets could not be saved!")
#View Recent Tweets
elif (choice == 2):
print("Recent Tweets")
print("--------------")
if len(tweet_list) == 0:
print("There are no recent tweets. \n")
for tweets in tweet_list[-5]:
print(tweets.get_author(), "-", tweets.get_age())
print(tweets.get_text(), "\n")
#Search Tweets
elif (choice == 3):
match = 0
tweet_list.reverse()
if tweet_list == []:
print("There are no tweets to search. \n")
search = input("What would you like to search for? ")
for tweets in tweet_list:
if (search in tweets.get_text()):
match = 1
if match = 1:
print("Search Results")
print("--------------")
print(tweets.get_author(), "-", tweets.get_age())
print(tweets.get_text(), "\n")
elif match == 0:
print("No tweets contained", search, "\n")
#Quit
elif (choice == 4):
print("Thank you for using the Tweet Manager!")
exit()
def display_menu():
print("Tweet Menu")
print("------------")
print()
print("1. Make a Tweet")
print("2. View Recent Tweets")
print("3. Search Tweets")
print("4. Quit")
print()
main()
There's no problem, the code is doing precisely what you told it to.
display_menu does exactly what the name implies: displays the menu. The main function calls that function inside a loop.
At no point do you actually ask for any input corresponding to the menu options.
display_menu always returns None - that's the default if you don't return anything.
Display menu does not retrieve any input into choice... Just displays the menu.
Thus, no if is matched and you loop indefinitely.
Your display_menu function doesn't actually give a value.
Change the last line of that function (print()) to
return input()
or if you are using python 2.x
return raw_input()

Continuous results from a single function call

I am extremely new to Python, and to programming in general, so I decided to write some basic code to help me learn the ins and outs of it. I decided to try making a database editor, and have developed the following code:
name = []
rank = []
age = []
cmd = input("Please enter a command: ")
def recall(item): #Prints all of the information for an individual when given his/her name
if item in name:
index = name.index(item) #Finds the position of the given name
print(name[index] + ", " + rank[index] + ", " + age[index]) #prints the element of every list with the position of the name used as input
else:
print("Invalid input. Please enter a valid input.")
def operation(cmd):
while cmd != "end":
if cmd == "recall":
print(name)
item = input("Please enter an input: ")
recall(item)
elif cmd == "add":
new_name = input("Please enter a new name: ")
name.append(new_name)
new_rank = input("Please enter a new rank: ")
rank.append(new_rank)
new_age = input("Please input new age: ")
age.append(new_age)
recall(new_name)
else:
print("Please input a valid command.")
else:
input("Press enter to quit.")
operation(cmd)
I want to be able to call operation(cmd), and from it be able to call as many functions/perform as many actions as I want. Unfortunately, it just infinitely prints one of the outcomes instead of letting me put in multiple commands.
How can I change this function so that I can call operation(cmd) once, and call the other functions repeatedly? Or is there a better way to go about doing this? Please keep in mind I am a beginner and just trying to learn, not a developer.
Take a look at your code:
while cmd != "end":
if cmd == "recall":
If you call operation with anything than "end", "recall" or "add", the condition within while is True, the next if is also True, but the subsequent ifs are false. Therefore, the function executes the following block
else:
print("Please input a valid command.")
and the while loop continues to its next lap. Since cmd hasn't changed, the same process continues over and over again.
You have not put anything in your code to show where operator_1, operator_2, and operator_3 come from, though you have hinted that operator_3 comes from the commandline.
You need to have some code to get the next value for "operator_3". This might be from a list of parameters to function_3, in which case you would get:
def function_3(operator_3):
for loopvariable in operator_3:
if loopvariable == some_value_1:
#(and so forth, then:)
function_3(["this","that","something","something else"])
Or, you might get it from input (by default, the keyboard):
def function_3():
read_from_keyboard=raw_input("First command:")
while (read_from_keyboard != "end"):
if read_from_keyboard == some_value_1:
#(and so forth, then at the end of your while loop, read the next line)
read_from_keyboard = raw_input("Next command:")
The problem is you only check operator_3 once in function_3, the second time you ask the user for an operator, you don't store its value, which is why its only running with one condition.
def function_3(operator_3):
while operator_3 != "end":
if operator_3 == some_value_1
function_1(operator_1)
elif operator_3 == some_value_2
function_2
else:
print("Enter valid operator.") # Here, the value of the input is lost
The logic you are trying to implement is the following:
Ask the user for some input.
Call function_3 with this input.
If the input is not end, run either function_1 or function_2.
Start again from step 1
However, you are missing #4 above, where you are trying to restart the loop again.
To fix this, make sure you store the value entered by the user when you prompt them for an operator. To do that, use the input function if you are using Python3, or raw_input if you are using Python2. These functions prompt the user for some input and then return that input to your program:
def function_3(operator_3):
while operator_3 != 'end':
if operator_3 == some_value_1:
function_1(operator_3)
elif operator_3 == some_value_2:
function_2(operator_3)
else:
operator_3 = input('Enter valid operator: ')
operator_3 = input('Enter operator or "end" to quit: ')
looks like you are trying to get input from the user, but you never implemented it in function_3...
def function_3(from_user):
while (from_user != "end"):
from_user = raw_input("enter a command: ")
if from_user == some_value_1:
# etc...

Categories

Resources