Quitting Menu Generates Error When User Re-Enters - python

I am pretty new to Python and am still figuring out the kinks as I go. I have a program that I've had a lot of assistance with writing that I've been perfecting and am having an issue as I go about debugging it that I cannot seem to resolve on my own so I wanted to see if anyone had any suggestions. When I run the menu() function and then select 'a' which calls the function thankyou() (NOTE: I left the other functions in that aren't throwing the errors but I just put in calls back to the menu() function because it would have become an even longer, cumbersome post with so much code); when I call thankyou() and I enter in either a new or existing name and then get to the point where I've set it up to ask for a donation amount (it is also able to accept 'Q' or 'q' to quit back to menu()) if I enter 'q' and go back to the menu and then proceed back to the thankyou() function and select the name that was entered the first time (whether it was newly created or it existed in the pre-assembled dictionary) once I get back to the donation solicitation section and enter in a numerical entry, I get the following error(s):
Traceback (most recent call last):
File "C:/FILEPATH.py", line 305, in <module>
menu() # Program starts here
File "C:/FILEPATH.py", line 64, in menu
switch_function.get(usr_sel)() # get user entry from dict
File "C:/FILEPATH.py", line 113, in thankyou
list(donor_dict.values())[get_index][1]) # current amt/ var from dict{[val]}
IndexError: list index out of range
I am trying to understand what is happening here so that I can figure out how to account for/prevent it. Does anyone have any ideas on what is causing this to happen and how I can address it? Thanks.
Code:
locale.setlocale(locale.LC_ALL, '')
today = time.strftime("%m/%d/%Y")
spacing = '- ' * 56 # formatting for DONOR header
donor_dict = {'Columns': ['NAMES', 'DONATION AMOUNT', 'NUMBER OF GIFTS', 'AVG. GIFTS'],
'Rudolph Soares': ['Rudolph Soares', 1335, 3, 445], # Donor info
'Josef Mistretta': ['Josef Mistretta', 7500, 4, 1875],
'Joye Agostini': ['Joye Agostini', 600, 2, 300],
'Rachelle Levan': ['Rachelle Levan', 12100, 5, 2420],
'Vena Ussery': ['Vena Ussery', 4000, 8, 500],
'Efrain Lager': ['Efrain Lager', 795, 9, 88.34],
'Mee Heine': ['Mee Heine', 4600, 4, 1150],
'Tanya Essex': ['Tanya Essex', 75000, 2, 37500]}
# ------------------------------------------------- PROCESSING --------------------------------------------------------
def menu():
"""Display menu of options to toggle between to perform separate actions"""
header = "-" * 110 # formatting for header
title = ' ' * 48 + "MAIL ROOM MENU" # title display
directions = "Select one of the three options:" # directions to user for menu
optA = "[A] Send a Thank you" # option(s) for menu
optB = "[B] Create a Report"
optC = "[C] Create Letters for All Donors"
optD = "[D] Quit"
whole_menu_header = header + '\n' + title + '\n' + header # header strung together as one uni
while True:
print(whole_menu_header) # display header
print(directions.center(110, ' '), '\n') # center directions with header display
print(optA + optB.center(37, ' ') + optC.center(36, ' ') + optD.center(25, ' ') + '\n')
switch_function = {
'A': thankyou, # dictionary holding menu options
'B': createreport,
'C': writeletters,
'D': quit_program,
}
try:
usr_sel = (input("Menu Selection: ")).upper() # user input for menu
switch_function.get(usr_sel)() # get user entry from dict
except KeyError:
print("Invalid Entry! Only enter A, B, C, or D.") # display error on any other entry
continue # continue back to start of menu
def thankyou():
"""Function enables user to add to dictionary data (adding new donors and donation amounts as well as
number of donations and average donations for new keys, and also updates existing keys."""
print("Leaving menu...\n")
while True:
print("Enter the name of the person you are writing to (or enter 'list' to see a list of names or Q to quit) ")
fname_prompt = input("First Name: ").strip().capitalize() # first name variable (strip any spaces)
if fname_prompt.upper() == "Q": # if Q, then quit to menu()
menu()
elif fname_prompt.lower() == "list":
displaylist()
else:
lname_prompt = input("Last Name: ").strip().capitalize() # last name variable
if lname_prompt.upper() == "Q": # if Q, back to menu
menu()
elif lname_prompt.lower() == "list": # if list, then list display
displaylist()
else:
key = fname_prompt + " " + lname_prompt
if key in donor_dict.keys():
existing_donor = input(
"That value is already in the list! Do you want to proceed with that selection? (Y/N): ")
if existing_donor.upper() == "Y": # if user proceeds, print display
donation_amt_str = input("Enter in the donation amount from Donor {0}: $".format(key))
if donation_amt_str.lower() == 'q':
menu()
try:
donation_amt = int(donation_amt_str)
except ValueError:
print("Error: invalid entry.\n")
else:
print(
'{0} has donated ${1:,.2f}'.format(key, donation_amt)) # display name and donation amt
int(donation_amt)
get_index = 0 # index variable
for item in range(0, len(donor_dict)): # set index var to current name
if list(donor_dict.values())[item][0] == key:
get_index = item
break
firstname = list(donor_dict.values())[get_index][0].split(' ', ).pop(
0) # separate first name, create variable
current_donations = int(
list(donor_dict.values())[get_index][1]) # current amt/ var from dict{[val]}
sum_donations = current_donations + donation_amt # sum of all donations (current + new)
list(donor_dict.values())[get_index][1] = float(sum_donations) # update sum
num_donations = int(list(donor_dict.values())[get_index][2]) + 1 # num donations = self + 1
list(donor_dict.values())[get_index][2] = num_donations # update num of donations
list(donor_dict.values())[get_index][3] = averagedonations(sum_donations,
num_donations) # update avg
email_display = str(
input("Display Donor Email? (Y/N or Q): ")) # ask user if they want to to
if email_display.upper() == "Y": # write email with name/amount
print(spacing)
print('Dear {0}, \n\nThank you for your continued support through your \
contribution of ${1:,.2f} towards our Foundation\'s fundraising goal.\n\nBest wishes,\n\
Foundation Board of Directors\n'.format(firstname, sum_donations))
print(spacing)
elif email_display.upper() == 'Q':
menu()
else:
continue
else:
add_name = str(input("That name is not in the Donor list. Do you want to add it to the list? (Y/N) "))
if add_name.upper() == "Y": # if input response == "Y", proceed
pair = {key: [key]}
donor_dict.update(pair)
displaylist()
num_donations = 1 # add new item to new name index
donation_amt_str = input("Enter in the donation amount from Donor {0}: $".format(key))
if donation_amt_str.lower() == 'q':
menu()
try:
donation_amt = int(donation_amt_str)
except ValueError:
print("Error: Invalid entry.\n")
else:
print('{0} has donated ${1:,.2f}'.format(key, donation_amt))
get_index = 0 # counter, start at 0
for item in range(0, int(len(list(donor_dict.values())))): # for items in donor_dict
if list(donor_dict.values())[item][0] == key: # if item at[0] == full_name
get_index = item # set index to item
break
# noinspection PyTypeChecker
list(donor_dict.values())[get_index].append(
donation_amt) # append donation amount to end of current lst [don_idx]
# noinspection PyTypeChecker
list(donor_dict.values())[get_index].append(num_donations) # append donation count to end
avg = averagedonations(donation_amt, num_donations)
list(donor_dict.values())[get_index].append(avg) # append average to end of current index
firstname = list(donor_dict.values())[get_index][0].split(' ', ).pop(
0) # separate first name, create variable
email_display = str(input("Display Donor Email? (Y/N): ")) # ask user if they want to
if email_display.upper() == "Y": # print email message
print(spacing) # if Y, then print
print('Dear {0}, \n\nThank you for your continued support through your \
contribution of ${1:,.2f} towards our Foundation\'s fundraising goal.\n\nBest wishes,\n\
Foundation Board of Directors\n'.format(firstname, donation_amt))
print(spacing)
elif email_display.upper() == 'Q':
menu()
else:
continue
def createreport():
"""Function creates organized report of donor information based on current dictionary contents.
Information is sorted in descending order based on total donation amounts."""
print("Leaving menu...")
while True: # continual loop unless user terminates
proceed = str(input("Generate Donor report? (Y/N): ")) # solicit user response to proceed
if proceed.upper() == "Y": # if user indicates yes
input("Generating Donor report... [Press Enter]") # on Enter press, proceed
new_list = list(donor_dict.values())[1:] # blank list to hold only values after headers
new_list.sort(key=lambda sort_on: sort_on[1], reverse=True) # sort list based on donation totals
lst_heading = list(donor_dict.values())[0:1] # container for only header
final_lst = lst_heading + new_list # join sorted list back with header
print(spacing)
print('{:>15s}'.format(str(final_lst[0][0])), end='') # format header for display
print(' |{:>20s}'.format(str(final_lst[0][1])), end='')
print(' |{:>19s}'.format(str(final_lst[0][2])), end='')
print(' |{:>15s}'.format(str(final_lst[0][3])))
print(spacing)
for i in range(1, int(len(final_lst))): # format list contents
print('{:>20s}'.format(str(final_lst[i][0])), end='')
print(' ${:>10,.2f}{:>17}'.format(float(final_lst[i][1]), int(final_lst[i][2])), end='')
print(' ${:>10,.2f}'.format(float(final_lst[i][3])))
else:
back_to_menu = str(input("Do you want to quit back to the main menu? (Y/N): ")) # escape sequence
if back_to_menu.upper() == "Y":
input("Quitting... [Press Enter]")
menu()
else:
continue # if no esc, then continue loop
def writeletters():
"""Function writes donor letter to file in user-directed file path"""
print("Leaving menu...")
names_list = [] # empty list to hold list of donor_dict names w/o whitespace (for filenames)
first_names = [] # first names separated out to be used for letters
default = os.getcwd() # get and assign current directory to variable
default = default + "\\" # format default so that it will be accepted (will work with Windows)
while True:
msg = input("Proceed to write letters to all donors in donor list? (Y/N) ") # if user selects Y, proceed
if msg.upper() == "Y": # check input
try:
working_directory = str(input('\nEnter the file path where you want to write the letters - '
'don\'t forget to use ''two \n\'\\\\\' as file separators to make sure'
' it is compatible if using Windows - (e.g. \'C:\\\\\': '))
except Exception as e: # exception handler - prints line of error, and type
print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
# working directory variable assignment by user - if blank, use default
if working_directory == "": # check for input on working_directory
working_directory = default
for x in range(int(len(donor_dict))): # for items in the span of donor_dict
firstname = list(donor_dict.values())[x][0] # firstname = donor_dict at index[item], column[0]
firstname = firstname.split(' ', ).pop(0) # format var to split on whitespace (only first name)
first_names.append(firstname) # append this value to empty list first_names
for i in range(int(len(list(donor_dict.values())))): # for items in the span of donor_dict
elem = list(donor_dict.values())[i][0] # elem = donor_dict at index[i], column[0]
elem = elem.replace(" ", "") # format name w/o whitespace
names_list.append(elem) # append to name_list
for names in range(1, int(len(names_list))): # omit header (range 0), for each name in names_list[]
try:
with open(working_directory + str(names_list[names]) + '.txt',
'a') as filename: # create files/file-names
filename.write(today) # write current date (mm/dd/yy)
filename.write('\n\nDear {0}, \n\nThank you for your continued support through your contribution '
'of {1} towards our Foundation\'s fundraising goal.\n\nBest wishes,\n'
'Foundation Board of Directors'
'\n'.format(str(first_names[names]),
locale.currency(list(donor_dict.values())[names][1], grouping=True)))
except Exception as e: # exception handler - prints line of error, and type
print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
# print letter message (first name and donation amount)
print("Files being written to " + working_directory + "...")
print("Done!") # message to user advising where files are going, and when it is done
elif msg.upper() == "N": # if user selected "N" for msg = input()
input("Exiting back to menu [Press ENTER]") # message to user, leaving this function
break # break out of while-loop - back to menu()
else:
print("That's an unrecognized value! Only Y or N are accepted.")
continue # invalid input, warning message: back to beginning of function
def quit_program():
"""Function quits all processes"""
input("Exiting Program...[Press ENTER]") # I use PyCharm and exit() w/o import worked fine but
from sys import exit # iPython was not running exit() without importing it from sys
exit() # so to avoid issues, I just kept this here
def displaylist():
"""Function returns current dictionary contents (names only)"""
cut_off = int(len(list(donor_dict.values())) / 2) # where list breaks for next line
if int(len(list(donor_dict.values()))) - 1 % 2 != 0: # even/odd check
for i in range(0, int(len(list(donor_dict.values())) - int(len(list(donor_dict.values())) - 2) / 2)):
if i == 0: # header check
print(spacing)
print('{:>44s}'.format(str(list(donor_dict.values())[i][0]))) # print Donor Name header
print(spacing)
elif cut_off + i >= len(list(donor_dict.values())): # if cut_off + i exceeds len(list)
print('{:>30s}'.format(list(donor_dict.values())[i][0])) # only print i (not cut_off + i)
continue
else:
print('{:>30s}'.format(list(donor_dict.values())[i][0]),
'{:>35s}'.format(list(donor_dict.values())[cut_off + i][0]))
else:
for i in range(0, int(len(list(donor_dict.values())) / 2)):
if i == 0: # header check
print(spacing)
print('{:>44s}'.format(str(list(donor_dict.values())[i][0]))) # print Donor Name header
print(spacing)
else:
print('{:>30s}'.format(list(donor_dict.values())[i][0]),
'{:>35s}'.format(list(donor_dict.values())[cut_off + i][0]))
print()
def averagedonations(donations, num):
"""Returns average of donor's gifts"""
sumgifts = donations
numgifts = num
average_donation = sumgifts / numgifts
return average_donation
# -------------------------------------------------- DISPLAY ----------------------------------------------------------
menu() # Program starts here

This error actually happens only when you enter a new donor name. When the user enters a new donor name and then press q to abort the donation, you already initialize the new donor entry with just pair = {key: [key]}, when in fact each entry is expected to have 4 items in the list, not just the person's name.
So when the user enters the same name next time and proceeds to enter a donation amount, your code at current_donations = int((donor_dict.values())[get_index][1]) cannot find the second item in the list for that donor, which is supposed to be the amount of the current donation.
To fix this, you simply have to change pair = {key: [key]} to pair = {key: [key, 0, 0, 0]} to properly initialize the list for the new entry.

Related

Add \n to the last element of a list, in a list of lists

So I have an external file where each line has a task formatted like this:
User, Title of task, Description of task, Date assigned, Due date, Completed (Yes/No)
I have created a list of lists where within the main list are lists of the line above essentially where each element is separated from the ", ".
So it looks like this:
[['User', 'Title of task', 'Description of task', 'Date assigned', 'Due Date', 'Completed (Yes/No)']]
I am trying to change the last element of the last list to include "\n" at the end.
Here is the code I implemented:
with open('tasks.txt', 'w') as f2:
count = 0
for i in list_of_tasks:
count += 1
if count == len(list_of_tasks):
list_of_tasks[i][-1] = str(f"{list_of_tasks[i][-1]}\n")
f2.write(", ".join(i))
else:
f2.write(", ".join(i))
This is the error I get:
list_of_tasks[i][-1] = str(f"{list_of_tasks[i][-1]}\n")
~~~~~~~~~~~~~^^^
TypeError: list indices must be integers or slices, not list
Ultimately what I'm trying to achieve is to edit parts of each line in this external file. The initial problem I have is the spacing after writing to the file gets messed up hence I'm trying to figure out how to add \n to the last element in the final list in this list of lists.
if it helps here's the full function:
def view_mine(username):
# opens tasks.txt as read only and assigns it as a variable named f1
with open('tasks.txt', 'r') as f1:
x = 1
list_of_tasks= []
other_tasks = []
for line in f1:
line3_split = line.split(', ')
if line3_split[0] == username:
user_format = f"""
Task {x}: {line3_split[1]}
Assigned to: {line3_split[0]}
Date assigned: {line3_split[3]}
Due date: {line3_split[4]}
Task complete? {line3_split[5]}
Task description:
{line3_split[2]}
"""
print(user_format)
x += 1
list_of_tasks.append(line3_split)
else:
other_tasks.append(line3_split)
selection = int(input(f"Which task do you want to select (1-{x-1}) or enter '-1' to return to main menu? ")) -1
if selection == -2:
return
else:
mark_or_edit = int(input(f"To mark as complete enter '1'. To edit the task enter '2'."))
if mark_or_edit == 1:
if list_of_tasks[selection][-1] == "No":
list_of_tasks[selection][-1] = "Yes\n"
elif list_of_tasks[selection][-1] == "No\n":
list_of_tasks[selection][-1] = "Yes\n"
elif mark_or_edit == 2:
user_or_date = int(input("To edit user assigned enter '1'. To edit due date enter '2'. "))
if user_or_date == 1:
user_check = input("Which user do you want to assign this task to? ")
existing_names_list = []
with open('user.txt', 'r') as f:
for line in f:
existing_names = line.split(', ')
existing_names_list.append(existing_names[0])
if user_check in existing_names_list:
list_of_tasks[selection][0] = user_check
else:
print("User does not exist.")
elif user_or_date == 2:
new_date = input("Enter the new due date (XX XXX XXXX): ")
list_of_tasks[selection][4] = new_date
with open('tasks.txt', 'w') as f2:
count = 0
for I in list_of_tasks:
count += 1
if count == len(list_of_tasks):
list_of_tasks[i][-1] = str(f"{list_of_tasks[i][-1]}\n")
f2.write(", ".join(i))
else:
f2.write(", ".join(i))
for i in other_tasks:
f2.write(", ".join(i))
return
The problem is in:
for i in list_of_tasks
In this situation i is a string and you are trying to use it as index in your list.
I am not sure what you are trying to accomplish exactly, but I think your code has some logical inaccuracies. I hope the following code gets the job done:
with open('tasks.txt', 'w') as f2:
count = 0
for sub_list in list_of_tasks:
for i in range(len(sub_list)):
if i == len(sub_list) - 1:
temp = sub_list[i] + '\n'
f2.write(temp)
else:
f2.write(sub_list[i] + ', ')
The output of the above code for the list you provided is:
User, Title of task, Description of task, Date assigned, Due Date, Completed (Yes/No)
with '\n' included in the end, even if it is not obvious.
It seems that you have a list of lists, so a 2D array, in which every element is a string. So you have to loop once for the first dimension (so for each list) and then for the second dimension(so for each string in list). Having every string each time, you are able to create the sentence you are trying to.

Order generator program

I am trying to make a short program which will take user input, append the input to a list and then randomly determine the order of the elements in the list.
this is what I thought out:
from random import choice
participants = []
prompt = "\nPlease enter players first name: "
prompt += "\nPlease enter 'q' when all players have been entered: "
while True:
user = input(prompt)
if user == 'q':
break
print(f"There are {slot} participants")
else:
participants.append(user)
slot = len(participants)
print("\n\n")
for participant in participants:
print(f"{participant}")
print(f"So far, there are {slot} participants")
while participants:
for participant in participants:
person_of_choice = choice(participants)
person_in_question = participants.remove(person_of_choice)
print(person_in_question)
However, I am getting the following output
Mark Stark Dark So far, there are 3 participants
Please enter players first name: Please enter 'q' when all players
have been entered: q None None None
How do I change the ordering from none into their names?
I've changed a few things in the code, and the changes are commented out with ##.
you can try it to see the output.
from random import choice
participants = []
prompt = "\nPlease enter players first name: "
prompt += "\nPlease enter 'q' when all players have been entered: "
# init slot to zero
slot = 0
while True:
user = input(prompt)
if user == 'q':
print(f"There are {slot} participants")
## if you want to use `print` function before `break`,
## you must put the `break` statement under the `print` function
break
else:
participants.append(user)
slot = len(participants)
print("\n\n")
for participant in participants:
print(f"{participant}")
print(f"So far, there are {slot} participants")
while participants:
for participant in participants:
person_of_choice = choice(participants)
print(person_of_choice)
# person_in_question = participants.remove(person_of_choice)
## person_in_question is None, because `remove` always return None
## you can this from here https://docs.python.org/3/tutorial/datastructures.html
participants.remove(person_of_choice)

Proper use of class and dict from user input

I've been struggling with my code for a class project and am in need of some help. I am not sure if I need to have a nested dictionary or list of dict or just use class in a list or dict. I've struggled to find the answers and could use some help with my code.
Should I just use list instead or am I thinking of this the right way, having the values stored in a dictionary or nested dict of some kind.
I'm especially at a loss for menu==3 #delete an item because as it is now I can only delete one attribute but what I need is to delete a whole property by property ID if possible
As you can probably tell I'm quite confused by now and would really appreciate any help from more experienced programmers.
inventory = {}
#class & constructor
class Property:
def __init__(self, propertyID, address, city, state, zipcode, squarefeet, modelname, salestatus):
self.propertyID = propertyID
self.address = address
self.city = city
self.state = state
self.zipcode = zipcode
self.modelname = modelname
self.squarefeet = squarefeet + 'Square Feet'
self.salestatus = salestatus
def print_Property(o):
if not isinstance(o, Property):
raise TypeError('print_Property(): requires a Property')
print('The property selected is Property ID: {} located at {} {} {} The Sqare footage is {}, {} model, Current status: {}'. format(o.propertyID,o.addresss, o.city, o.state, o.zipcode, o.squarefeet, o.modelname, o.salestatus))
def main():
print('What would you like to do today?')
print('----------------------------------------')
print('1. Add a new item to the Inventory')
print('2. Update an Existing item in the Inventory')
print('3. Delete an existing item from the Inventory')
print('4. View the current item inventory')
print('5. Print the Inventory to a text file')
print('------------------------------')
while True:
try:
menu = int(input('Type a number 1-5'))
if menu == 1: #Add data
print('Add a new property to the inventory...')
propertyID = input('Enter the property Listing ID:') #User inputting a property ID
inventory['Property ID']= propertyID
address = input('Enter the property address:') #User inputting an address
inventory['Address']= address
city = input('Enter property city:') #User inputting a city
inventory['City']= city
state = input('Enter property state:') #User inputting a state
inventory['State']= state
zipcode = int(input('Enter the property zipcode:')) #User inputting a zipcode
inventory['Zipcode']= zipcode
modelname = input('Enter property model name:') #User inputting a property model name
inventory['Model Name']= modelname
squarefeet = int(input('Enter the sqaure footage of the property:')) #User inputting the sqaure footage for the property
inventory['Square Footage']= squarefeet
salestatus = input('Enter the property status:(Is the home sold, available, or under contract?):') #User inputting the property status
inventory['Current Staus']= salestatus
print('The following properties are in the inventory now:')
print(inventory)
#break
elif menu == 2: #Update data
print('Update an item from the inventory...')
print (inventory)
itemreplace = input("Enter the name of the attribute you wish to replace:")
itemupdate = input("Enter the new information for that attribute now:")
inventory[itemreplace]= itemupdate
print(inventory)
elif menu == 3: #Delete data
print("Which property do you want to delete?")
print(inventory)
itemdel = input("Enter the Property ID of the property to delete.")
if itemdel in inventory:
del inventory[itemdel]
print(inventory)
elif menu == 4: #View data
print(inventory)
elif menu == 5: #Print data
output = open("PropertyData.txt", "w")
for item in inventory:
output.write("%s\n" % item)
print('Text file \'PropertyData.txt\' has been created.')
else:
print('That number is not valid. Please try 1-5.')
except ValueError: #throw an error for anything that is not a number
print('You may only select values 1-5. (ex.: 2)')
if __name__ == '__main__': main()
#Lucas is right. Here is a fully working ( I think :) ) system:
import json
class Property:
def __init__(self, propertyID, address, city, state, zipcode, squarefeet, modelname, salestatus):
self.propertyID = propertyID
self.address = address
self.city = city
self.state = state
self.zipcode = zipcode
self.modelname = modelname
self.squarefeet = squarefeet
self._sqfeet_description = str(squarefeet) + ' Square Feet'
self.salestatus = salestatus
def __str__(self):
o = self
return 'Property ID: {}. Address: {}, {}, {}, {}. Size: {} sq feet, {} model. Status: {}.'.format(o.propertyID,o.address, o.city, o.state, o.zipcode, o.squarefeet, o.modelname, o.salestatus)
def as_json(self):
return {x:y for x,y in self.__dict__.items() if not x.startswith("_")}
def int_input(prompt, range=None):
while True:
ans = input(prompt)
if not ans.isnumeric():
print("Please enter a valid number")
continue
ans = int(ans)
if range == None:
return ans
if ans not in range:
print(f"Please enter a number between {min(range)} and {max(range)}")
continue
return ans
inventory = []
def main():
print('What would you like to do today?')
print('----------------------------------------')
print('1. Add a new item to the Inventory')
print('2. Update an Existing item in the Inventory')
print('3. Delete an existing item from the Inventory')
print('4. View the current item inventory')
print('5. Print the Inventory to a text file')
print('------------------------------')
while True:
menu = int_input("Choose an option 1-5", range(1,6))
if menu == 1:
# add data
propertyID = input('Enter the property Listing ID:') #User inputting a property ID
address = input('Enter the property address:') #User inputting an address
city = input('Enter property city:') #User inputting a city
state = input('Enter property state:') #User inputting a state
zipcode = int_input('Enter the property zipcode:') #User inputting a zipcode
modelname = input('Enter property model name:') #User inputting a property model name
squarefeet = int_input('Enter the sqaure footage of the property:') #User inputting the sqaure footage for the property
salestatus = input('Enter the property status:(Is the home sold, available, or under contract?):') #User inputting the property status
this_property = Property(
propertyID,
address,
city,
state,
zipcode,
squarefeet,
modelname,
salestatus)
inventory.append(this_property)
print('The following properties are in the inventory now:')
print(*("\t" + str(i) for i in inventory), sep="\n")
print()
elif menu == 2:
# update data
while True:
propertyID = input("Enter the property id: ")
this_property = [x for x in inventory if x.propertyID == propertyID]
if not this_property:
print("That property doesn't exist")
continue
this_property = this_property[0]
break
lookup = {
"propertyID": str,
"address":str,
"city":str,
"state":str,
"zipcode":int,
"modelname":str,
"squarefeet":int,
"salestatus":str
}
while True:
detail_name = input("Enter the detail you wish to change")
if detail_name not in lookup:
print("That detail does not exist")
continue
break
if lookup[detail_name] == int:
new = int_input("Enter the new value:")
else:
new = input("Enter the new value:")
setattr(this_property, detail_name, new)
elif menu == 3:
# delete
while True:
propertyID = input("Enter the property id: ")
this_property = [i for i, x in enumerate(inventory) if x.propertyID == propertyID]
if not this_property:
print("That property doesn't exist")
continue
this_property = this_property[0]
break
del inventory[this_property]
elif menu == 4:
# print inventory
print('The following properties are in the inventory now:')
print(*("\t" + str(i) for i in inventory), sep="\n")
print()
elif menu == 5:
# save
new_inv = [x.as_json() for x in inventory]
with open("output.txt", "w") as f:
json.dump(new_inv, f)
if __name__ == '__main__':
main()
If you want to save your properties and be able to load them again, add this method to Property:
class Property:
...
#classmethod
def from_json(cls, json_code):
c = cls(*(None for _ in range(8)))
for x,y in json_code.items():
setattr(c, x, y)
return c
and this function to the body of your program:
def load_from_file():
with open("output.txt") as f:
for item in json.load(f):
inventory.append(Property.from_json(item))
and then call the function at the start:
if __name__ == '__main__':
load_from_file()
main()
(obviously make sure the file exists before that though - just save [] to output.txt before running the program for the first time)
The easiest solution is to use a list of Property objects, where each element in a list is an individual property. Adding properties to the inventory means creating a new object, filling in all the fields and appending it to the inventory list.

I am trying to create an address book program that will append user input to its appropriate list

I am having trouble getting past writing user input to my list what am I doing wrong here? This is an address book program that I am writing, the assignment is to create parallel lists that will store user input data in the appropriate list using a for or while loop. The program must also have a search function which you can see is at the bottom of the code. My issue that I am having is getting the program to store data within my lists. Unfortunately lists are something that give me lots of trouble I just cant seem to wrap my head around it no matter how much research I have done. The issue im running into is the append.data function when trying to write lastname and firstname to my list of names. what am I doing wrong?
#NICHOLAS SHAFFER
#5/11/2016
#MYADDRESSBOOK
def menu():
index = 0
size = 100
count = 0
answer = raw_input("Are You Creating An Entry [Press 1] \nOr Are You Searching An Entry [Press 2] ")
if answer == "1" :
print ("This is where we create")
append_data(index, size, count)
elif answer == "2" :
print ("this is where we search")
search_database()
name[size]
phone[size]
addresss[size]
# IF we are creating
def append_data(index, size, count):
# collect information
for index in range(0, 100):
optOut = 'no'
while optOut == 'no':
lastname[count] = raw_input("What is the persons last name? ")
firstname[count] = raw_input("What is the persons first name? ")
phone[count] = raw_input("What id the persons phone number? ")
address[count] = raw_input("What is the persons address? ")
count = count + 1
print 'Would you like to create another entry?'
optOut = raw_input('Would you like to create another entry? [ENTER YES OR NO]:')
if optOut == 'yes':
menu()
#create string to print to file
#print temp1
#print (firstname + " " + lastname + ", " + phone + ", " + email + ", " + address)
print listName[index]
print listPhone[index]
print listAddress[index]
print 'file has been added to your addressbook sucessfuly'
menu()
# SEARCHING FOR A RECORD
def search_database():
searchcriteria = raw_input("Enter your search Criteria, name? phone, or address etc ")
print searchcriteria
if searchcriteria == "name":
temp1 = open(listName[lastname, firstname],"r")
print temp1
if searchcriteria == "phone":
temp1 = open(listPhone[0], "r")
print temp1
if searchcriteria == "address":
temp1 = open(listAddress[0], "r")
print temp1
else:
print "sorry you must enter a valid responce, try again."
menu()
for line in temp1:
if searchcriteria in line:
print line
errorMessage()
# USER DID NOT PICK CREATE OR SEARCH
def errorMessage():
print ("Incorrect Answer")
exit()
menu()
Your error message says it all:
line 34, in append_data lastname[count]... NameError: global name 'lastname' is not defined
You'll get this same error if you type lastname[4] in any interpreter -- you've simply never defined a list called lastname, so you can't access items in it. In the short term, you can fix this with a line
lastname = list()
You're going to end up with more troubles though; lastname won't be accessible outside the function where you define it, neither will listName. I'd probably approach that by writing them into a data file/database, or maybe creating a quick class whose members will all have access to self.lastname.
My final append for lists thanks again Noumenon
def append_data(index, size, count):
lastnames = list()
if count < size -1:
lastname = raw_input("What is the persons last name? ")
lastnames.append(lastname)
print lastnames
firstnames = list()
if count < size - 1:
firstname = raw_input("What is the persons first name? ")
firstnames.append(firstname)
print firstnames
phones = list()
if count < size - 1:
phone = raw_input("What id the persons phone number? ")
phones.append(phone)
print phones
addresss = list()
if count < size - 1:
address = raw_input("What is the persons address? ")
addresss.append(address)
print addresss
listName = (lastnames, firstnames)
addressbook =(listName, phones, addresss)
index = index + 1
count = count + 1
print addressbook
optOut = raw_input('Would you like to create another entry? [Enter YES or NO]: ')
if optOut == 'YES':
menu()
print 'file has been added to your addressbook sucessfuly'
menu()

Python - Can't add more than 1 score to a list

Sorry if I get this wrong, this is my first post.
I wrote a program to keep a LIST of cricketers and their scores and adds new scores to their tally which works fine but when I add a new batsman, I can't add more than one score. Can anyone see what I'm doing wrong please I have been at this for two days now. Here is the code: -
import pickle
scores = [["Moe", 100], ["Curly", 50], ["Larry", 0]]
#setup the save function same as usual
def save_scores():
file = open("pickle.dat", "wb")
pickle.dump(scores, file)
file.close()
print('Scores Saved')
print()
#setup the load same as yours
def load_scores():
file = open("pickle.dat", "rb")
scores = pickle.load(file)
file.close()
print(scores)
print()
#print the scores to the screen
def print_scores():
for i in range(0,len(scores)):
print(scores[i])
print()
#add a score to the list
def add_score():
#first setup a flag like in a bubble sort. This will show if we find a name
flag = False
a = ''
#ask for the name and the new score
name = input("Enter your name: ")
score = int(input("Enter your score: "))
#now count through the list of names
for i in range (0,len(scores)):
#take out each name and store it in var a
a = (scores[i][0])
#strip the space off the end. Unfortunately, when Python stores names
#in a list it adds spaces to the end of them. The only way to strip them
#off is to put them in a variable first, hence a
a.replace(' ','')
#now we set the flag if we find the name we just typed in
if a == name:
#and add the score to the name in the list
scores[i].append(score)
flag = True
#if we get to here and the flag is still false then the name doesn't exist
#in the list so we add the name and the score to the list
if flag == False:
arr = (name,score)
scores.append(arr)
def print_menu():
print('1. Print Scores')
print('2. Add a Score')
print('3. Load Scores')
print('4. Save Scores')
print('5. Quit')
print()
menu_choice = 0
print_menu()
while True:
menu_choice = int(input("Type in a number (1-5): "))
if menu_choice == 1:
print_scores()
if menu_choice == 2:
add_score()
if menu_choice == 3:
print_scores()
if menu_choice == 4:
save_scores()
if menu_choice == 5:
print ("Goodbye")
break
Replace:
arr = (name,score)
with:
arr = [name,score]
The thing is you are using a tuple when a new player is added. But tuples are immutable in python you cannot modify them. That is the reason you are unable to append further scores to a new player. Replacing tuple with a list will fix the issue as lists are mutable.

Categories

Resources