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()
Related
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.
Good evening, I have a phonebook code but I am missing the delete feature. I cannot seem to make the delete feature work. All other features like insert, view, add contacts are working already.
I created a phnoebook txt file to store any entries.
phonebook = "d://phonebook.txt"
pbfile = open(phonebook, "a+")
pbfile.close
def show_main_menu():
''' Show main menu for Phone List '''
print("\n *** Phone List Menu ***\n"+
"------------------------------------------\n"+
"Enter 1, 2, 3 or 4:\n"+
"1: Display Your Contacts Records\n" +
"2: Add a New Contact Record\n"+
"3: Search your contacts\n"+
"4: Delete a Contact Record\n"+
"5: Quit\n**********************")
choice = input("Enter your choice: ")
if choice == "1":
pbfile = open(phonebook, "r+")
file_contents = pbfile.read()
if len(file_contents) == 0:
print("Phone List is empty")
else:
print (file_contents)
pbfile.close
user_entry = input("Press Enter to Return to Main Menu ...")
show_main_menu()
elif choice == "2":
enter_contact_record()
user_entry = input("Press Enter to Return to Main Menu ...")
show_main_menu()
elif choice == "3":
search_contact_record()
user_entry = input("Press Enter to Return to Main Menu ...")
show_main_menu()
elif choice == "4":
delete_contact_record()
user_entry = ("Please Enter to Return to Main Menu ...")
show_main_menu()
elif choice== "5":
print("Thanks for using Phone List")
else:
print("Wrong choice, Please Enter [1 to 5]\n")
user_entry = input("Press Enter to Return to Main Menu ...")
show_main_menu()
I added the main menu above to show the menu of the phone book, there should be another choice to delete a contact.
The following code is to search for contact. It will show if a contact is already in the phone book but will mention not on record if there is no contact by the name they searched.
def search_contact_record():
''' This function is used to searches a specific contact record '''
contact_search = input("Enter First name to search for contact record: ")
contact_search = contact_search.title()
pbfile = open(phonebook, "r+")
file_contents = pbfile.readlines()
found = False
for line in file_contents:
if contact_search in line:
print("You searched for:", end=" ")
print (line)
found=True
break
if found == False:
print("There's no contact Record in Phone List with name = " + contact_search )
The next function is to enter contact and add it to the phonebook txt file created in the beginning.
def enter_contact_record():
''' It collects contact info firstname, last name, email and phone '''
first = input('Enter First Name: ')
first = first.title()
last = input('Enter Last Name: ')
last = last.title()
phone = input('Enter Phone number: ')
email = input('Enter E-mail: ')
contact = ("[" + first + " " + last + ", " + phone + ", " + email + "]\n")
pbfile = open(phonebook, "a")
pbfile.write(contact)
print( "This contact\n " + contact + "has been added successfully!")
#def delete_contact():
show_main_menu()
I got confused on the part how to delete the contact from the txt phonebook. Last delete lines I have trying was the following
def delete_contact_record():
#Initiate a name variable
contact_delete = input('Enter the name of the contact you wish to delete: ').title()
pbfile = open(phonebook, "r+")
file_contents = pbfile.readlines()
found = False
for line in file_contents:
if contact_delete in line:
confirm = input('Are you sure you wish to delete '+contact_delete+' y/n?: ')
print(confirm)
if confirm == 'y':
del phonebook[contact_delete]
found = True
if found == False:
print('That contact does not exist! Return to the main menu to enter the contact')
it works up to the line asking for confirmation y/n. But when I enter Y, I get a TypeError: 'str' object does not support item deletion
Thank you.
Your main problem is that your phone book is a flat file. As such, a deletion is "rewrite the entire file, but without the deleted record."
This is, needless to say, very inefficient.
You will also have problems in the future with spurious matches for searches, since contact_search in line is perfectly happy to match parts of names.
Personally, I'd recommend using an SQLite3 database instead of a flat file (SQLite3 support is built in to Python). SQLite3 databases are actually single files, but you can use almost all of the SQL language to perform structured queries, and let it manage the file for you.
If writing SQL is too daunting, the SQLAlchemy Python package can help by making database tables work like Python classes.
Before I state my question I would like to start by saying that I am a beginner at Python programming. I am about half way through my first ever programming class. With that being said I have also researched and used the search engines to look for information on the topic I am working on but I have not found anything that has been either helpful or specific enough to my problem. I have looked through Stack Overflow including browsing the similar questions dialogue. My hope is that this will not be down voted or marked as a duplicate before I get any helpful information.
I am creating a contacts manager program that uses a list of contact names, email addresses, and phone numbers stored in a CSV file. My program should allow the user to display a list of all the contact names, add/delete contacts, and view specific contact information. I am having trouble with the final requirement. Everything else in the program is working and displaying in the console like it should. The code for the entire program is found below;
#!/user/bin/env python3
# Contacts Manager Program
#Shows title of program at start.
print("The Contact Manager Program")
print()
#Imports CSV Module
import csv
#Defines global constant for the file.
FILENAME = "contacts.csv"
#Displays menu options for user, called from main function.
def display_menu():
print("COMMAND MENU")
print("list - Display all contacts")
print("view - View a contact")
print("add - Add a contact")
print("del - Delete a contact")
print("exit - Exit program")
print()
#Defines write funtion for CSV file.
def write_contacts(contacts):
with open(FILENAME, "w", newline="") as file:
writer = csv.writer(file)
writer.writerows(contacts)
#Defines read function for CSV file.
def read_contacts():
contacts = []
with open(FILENAME, newline="") as file:
reader = csv.reader(file)
for row in reader:
contacts.append(row)
return contacts
#Lists the contacts in the list with the user inputs the "list" command.
def list_contacts(contacts):
for i in range(len(contacts)):
contact = contacts[i]
print(str(i+1) + ". " + contact[0])
print()
#List a specific contacts information when the user inputs the "view" command.
def view_contact(number):
#Adds contact to the end of the list when user inputs the "add" command.
def add_contact(contacts):
name = input("Name: ")
email = input("Email: ")
phone = input("Phone: ")
contact = []
contact.append(name)
contact.append(email)
contact.append(phone)
contacts.append(contact)
write_contacts(contacts)
print(name + " was added.\n")
#Removes an item from the list.
def delete_contact(contacts):
number = int(input("Number: "))
if number < 1 or number > len(contacts): #Display an error message if the user enters an invalid number.
print("Invalid contact number.\n")
else:
contact = contacts.pop(number-1)
write_contacts(contacts)
print(contact[0] + " was deleted.\n")
#Main function - list, view, add, and delete funtions run from here.
def main():
display_menu()
contacts = read_contacts()
while True:
command = input("Command: ")
if command.lower() == "list":
list_contacts(contacts)
elif command.lower() == "view": #Store the rest of the code that gets input and displays output in the main function.
view_contact(contacts)
elif command.lower() =="add":
add_contact(contacts)
elif command.lower() == "del":
delete_contact(contacts)
elif command.lower() == "exit":
break
else:
print("Not a valid command. Please try again.\n")
print("Bye!")
if __name__ == "__main__":
main()
I need the view_contact function to get a number as input from the user and then print the corresponding contact information that is related the the line number in the CSV file.
It looks like you storing contacts in form of lists in your .csv file. Use read_contacts to read all the contacts from that csv file, then get contact specified by number parameter. That's it.
def view_contact(number):
contacts = read_contacts()
specified_contact = contacts[number]
print("Name: ", specified_contact[0])
print("Email: ", specified_contact[1])
print("Phone: ", specified_contact[2])
The purpose of the two programs is to have twitter.py manage tweet.py by having the 5 most recent tweets that are saved in the program twitter.py to show up once you search and find it. There are four options, make a tweet, view recents tweets, search a tweet and quit. I'm having trouble saving because it keeps saying no recent tweets are found. Also I'm having trouble with the fact that I can't search for my tweets but that is probably the same reason as my first problem because they aren't being saved correctly. Thank you please help!!
tweet.py
import time
class tweet:
def __init__(self, author, text):
self.__author = author
self.__text = text
self.__age = time.time()
def get_author(self):
return self.__author
def get_text(self):
return self.__text
def get_age(self):
now = time.time()
difference = now - self.__time
hours = difference // 3600
difference = difference % 3600
minutes = difference // 60
seconds = difference % 60
# Truncate units of time and convert them to strings for output
hours = str(int(hours))
minutes = str(int(minutes))
seconds = str(int(seconds))
# Return formatted units of time
return hours + ":" + minutes + ":" + seconds
twitter.py
import tweet
import pickle
MAKE=1
VIEW=2
SEARCH=3
QUIT=4
FILENAME = 'tweets.dat'
def main():
mytweets = load_tweets()
choice = 0
while choice != QUIT:
choice = get_menu_choice()
if choice == MAKE:
add(mytweets)
elif choice == VIEW:
recent(mytweets)
elif choice == SEARCH:
find(mytweets)
else:
print("\nThanks for using the Twitter manager!")
save_tweets(mytweets)
def load_tweets():
try:
input_file = open(FILENAME, 'rb')
tweet_dct = pickle.load(input_file)
input_file.close()
except IOError:
tweet_dct = {}
return tweet_dct
def get_menu_choice():
print()
print('Tweet Menu')
print("----------")
print("1. Make a Tweet")
print("2. View Recent Tweets")
print("3. Search Tweets")
print("4. Quit")
print()
try:
choice = int(input("What would you like to do? "))
if choice < MAKE or choice > QUIT:
print("\nPlease select a valid option.")
except ValueError:
print("\nPlease enter a numeric value.")
return choice
def add(mytweets):
author = input("\nWhat is your name? ")
while True:
text = input("what would you like to tweet? ")
if len(text) > 140:
print("\ntweets can only be 140 characters!")
continue
else:
break
entry = tweet.tweet(author, text)
print("\nYour tweet has been saved!")
def recent(mytweets):
print("\nRecent Tweets")
print("-------------")
if len(mytweets) == 0:
print("There are no recent tweets. \n")
else:
for tweets in mytweets[-5]:
print(tweets.get_author, "-", tweets.get_age)
print(tweets.get_text, "\n")
def find(mytweets):
author = input("What would you like to search for? ")
if author in mytweets:
print("\nSearch Results")
print("----------------")
print(tweet.tweet.get_author(), - tweet.tweet.get_age())
print(tweet.tweet.get_text())
else:
print("\nSearch Results")
print("--------------")
print("No tweets contained ", author)
def save_tweets(mytweets):
output_file = open(FILENAME, 'wb')
pickle.dump(mytweets, output_file)
output_file.close()
main()
In twitter.py:add_tweets, mytweets is passed into the function and entry is created, but it is never added to mytweets. The created entry is lost after the function returns.
Your question was:
I'm having trouble saving because it keeps saying no recent tweets are
found.
Function add does not seem to be adding tweets anywhere. It creates a tweet.tweet instance, but it does not do anything with it.
You probably want to add the tweet to mytweets?
Another problem:
You initialize mytweets as a dicionary (tweet_dct = {}), but later you use it as a list (mytweets[-5]). It should be a list from start. And you probably want last five tweets (mytweets[-5:]), not just the fifth from the end.
On the sidenotes:
What you have here is not "two programs" - it is one program in two python files, or "modules"
Although there is nothing wrong with having getters (functions like get_author), there is no need for them in Python (see How does the #property decorator work?). Do youself a favour and keep it simple, e.g.:
class Tweet:
def __init__(self, author, text):
self.author = author
self.text = text
self.creation_time = time.time()
def get_age_as_string(self):
# your code from get_age
There will be time when you need private variables. When that happens, use a single leading underscore (self._author) until you fully understand what double underscore does and why.
Pickle is probably not the best way to store information here, but it is a good start for learning.
I am slightly stuck on my code. My knowledge of python is very limited but I am trying to quit the loop to display the items someone selects. I have tried if statements that don't work. Considered a def statement but not too sure how to implement it and Return is an idea but obviously needs the def statement to work.
Any help is much appreciated.
P.S I have no idea how to upload the CSV file but, the following link is what I am aiming to do: https://dl.dropboxusercontent.com/u/31895483/teaching%20delivered/FE/2013-14/Access%20-%20Prg/assignment/menu2.swf
import csv
f = open("menu.csv", "r") #Has items for the menu and is read only
spent = 0
order = []
menu = []
for line in f:
line = line.rstrip("\n")
dish = line.split(',')
menu = menu + [dish]
f.close()
#Menu imported into python, no need to leave file open
while True:
dishes = -1
for dish in menu:
if dishes == -1:
print ("Dish No".ljust(10), end="")
else:
print(str(dishes).ljust(10), end="")
print(dish[0].ljust(15), end="")
print(dish[1].ljust(30), end="")
print(dish[2].ljust(15), end="")
print(dish[3], end="\n\n")
dishes += 1
reply = input("Please choose your first item: ")
print()
spent = spent + float(menu[int(reply)+1][2])
order = order + [reply]
print(len(order), "choices made so far =", order, "and cost = £ ", spent)
print()
print ("Please choose an item from the menu (0-9 or press Q to end): ")
print()
All you need to do is check for the exit condition, and then use the break statement to break out of the loop.
while True:
# other stuff here
reply = input("Please choose a menu item:")
if reply.upper() == 'Q':
break # Break out of the while loop.
# We didn't break, so now we can try to parse the input to an integer.
spent = spent + float(menu[int(reply)+1][2])
This pattern of while True + other_code + if condition: break is pretty common, which has at least two benefits:
You're using accepted idioms, so you'll recognize them when you encounter them elsewhere.
Other people (including your future self) will be able to understand your code when they read it.
a cool trick that I like
my_menu_choices = iter(lambda : input("Please choose a menu item:").lower(),"q")
for i,dish in dishes:
print("%d. %s"%(i,dish))
print("Q. type q to QUIT")
my_menu_choices = list(my_menu_choices)
print("You Choose: %s"%my_menu_choices)