Rewriting CSV file in Python messes up index of rows - python

This is my entire project at the moment. The original CSV file has 4 rows with a contacts name, email, and phone information. The "list" "view" and "add" functions work fine until I use the "delete" function. In order to delete the desired line, I put the file in a list, deleted the row the user inputs, and rewrote the list into the CSV file with what appears to be good format.
import csv
print("Contact List\n")
print(" list - Display all contacts\n","view - View a contact\n","add - Add a contact\n", "del - Delete a contact\n", "exit - Exit program\n")
def main():
userCom = input("\nCommand: ")
if userCom == "list":
lists()
elif userCom == "view":
count()
elif userCom == "add":
add()
elif userCom == "del":
delete()
elif userCom == "exit":
exitt()
else :
print("Invaild input, try again")
main()
def count():
counter = 1
with open("contacts.csv") as file:
number = file.readline()
for line in file:
counter = counter +1
view(counter)
def lists():
with open("contacts.csv", newline="") as file:
reader = csv.reader(file)
counter = 0
for row in reader:
print(int(counter) + 1, ". ",row[0])
counter = counter+1
main()
def view(count):
num = input("Enter a contact's number to view their information: ")
while num.isdigit() == False or int(num) < 1 or int(num) > int(count):
print("Invaild input, try again")
view(count)
reader = csv.reader(open("contacts.csv"))
lines = list(reader)
print("Name: ",lines[int(num)-1][0],"\nEmail: ",lines[int(num)-1][1],"\nPhone Number: ",lines[int(num)-1][2])
main()
def add() :
name = input("Name: ")
email = input("Email: ")
phone = input("Phone: ")
added = [name,",",email,",",phone]
with open("contacts.csv", "a") as file:
for item in added:
file.write(item)
print(name, " was added.")
file.close()
main()
def delete():
deleted = input("Enter number to delete: ")
reader = csv.reader(open("contacts.csv"))
contacts = list(reader)
del contacts[int(deleted)-1]
with open("contacts.csv", "w") as file:
writer = csv.writer(file)
writer.writerows(contacts)
print("Number ",deleted," was deleted.")`enter code here`
file.close()
main()
main()
When I use delete and try the "list" or "view" features, I get this error message:
Traceback (most recent call last):
File "C:\Users\Test\Desktop\contacts_1.py", line 81, in <module>
main()
File "C:\Users\Test\Desktop\contacts_1.py", line 15, in main
delete()
File "C:\Users\Test\Desktop\contacts_1.py", line 72, in delete
main()
File "C:\Users\Test\Desktop\contacts_1.py", line 9, in main
lists()
File "C:\Users\Test\Desktop\contacts_1.py", line 35, in lists
print(int(counter) + 1, ". ",row[0])
IndexError: list index out of range
Any help helps!

This is because your row doesnt contain any line, so it doesn't even have the 0 index.
Yo must check if the list contain something before accessing any item inside:
if row:
print(row[0])
As I said in comment, your solution is flawed, because it will overflow the stack at some point. You should use an infinite loop instead of calling the main function again and again
def main():
while 1:
userCom = input("\nCommand: ")
if userCom == "list":
lists()
elif userCom == "view":
count()
elif userCom == "add":
add()
elif userCom == "del":
delete()
elif userCom == "exit":
exitt()
else:
print("Invaild input, try again")
# main()

Related

Type Error, Need a Y/N user confirmation. Python

I am working on a function that will delete records of individuals but before doing so, it will display:
Are you sure you want to delete record with Last Name: Apple, First Name: Amy ? Enter Y or N
I got through most of my function. I am having difficulty with this Yes or No part. The code I have for the delete function so far is as follows
def delete_student():
global student_info
global database
print("--- Delete Student ---")
roll = input("Enter a Last Name: ")
student_found = False
updated_data = []
with open(database, "r", encoding="utf-8") as f:
reader = csv.reader(f)
counter = 0
for row in reader:
if len(row) > 0:
if roll != row[2]:
updated_data.append(row)
counter += 1
else:
student_found = True
if student_found is True:
if input("Are you sure you want to delete record", roll, "(y/n) ") != "y":
exit()
with open(database, "w", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(updated_data)
print("Student ", roll, "deleted successfully")
else:
print("Record not found")
input("Press any key to continue")
This gives me a Type Error, I need to display the name of the person as confirmation before deleting the record. Y/N input.
Type Error:
Traceback (most recent call last):
File "/Users/jake./PycharmProjects/Munyak_Jacob_FinalProject/FileRecords.py", line 58, in <module>
delete_student()
File "/Users/jake./PycharmProjects/Munyak_Jacob_FinalProject/deleteRecord.py", line 27, in delete_student
if input("Are you sure you want to delete record", roll, "(y/n) ") != "y":
TypeError: input expected at most 1 argument, got 3
Process finished with exit code 1
input takes a single string as a parameter, but you've provided three. Construct a single string:
if input(f"Are you sure you want to delete record {roll} (y/n)? ") != "y":

Why is my code not posting the requested columns in main def?

I don't expect any coding answers, more just guidance. For my project I have to date-mine apple stock prices from a csv-file and implement it in my code. I provided a sample output below.
https://imgur.com/rPOPN1I
Right now, I am not getting any error messages but my code is not posting the columns requested from the csv.file. Are my definitions at fault or am I missing something else?
# Project No.: 5
# Author: burntchickennuget
# Description: making definitions, reading from a .csv file, validating input, data-mining,
f_list = list()
file_object = ()
my_tot = dict()
new_list = list()
def get_input_descriptor():
while True:
filename = input("Enter a file name: ")
if filename == 'table.csv':
with open(filename, "r") as infile:
infile.readlines()[1:]
# for line in lines:
# print(line.rstrip())
break
else:
print("Bad file name, try again")
return filename
def get_data_list(file_object, column_number):
dict = {}
for val in file_object:
date = val.split(",")[0]
data = float(val.split(",")[column_number])
dict[date] = data
return dict.items()
def average_data(new_list):
for date, price in new_list:
my_tot[date] = my_tot.get(date, 0) + float(price)
my_times[date] = my_times.get(date, 0) + 1
for key in my_tot:
f_list.append((float(my_tot[key] / my_times[key]), key))
def main():
get_input_descriptor()
column_number = int(input("Which column: "))
date_list = get_data_list(file_object, column_number)
final_list = average_data(date_list)
x = sorted(f_list)
print('Lowest 6:')
for tup in x[:6]:
print
tup[0], tup[1]
print('Highest 6:')
x = sorted(f_list, reverse=True)
for tup in x[:6]:
print
tup[0], tup[1]
while 1:
flag = input("do you want to continue? ")
if flag == '' or not flag[0].lower() in ['y', 'n']:
print("Please answer with a yes or no")
else:
break
if flag[0].lower() == 'y':
column = input("Which column: ")
print(column)
if flag[0].lower() == 'n':
print("Bye!")
if __name__ == "__main__":
main()
What can I try next?
Take a look around your get_input_descriptor method.
What are you returning from the method?
Where is the returned information being stored in the main method (is it being stored at all?)
What are you doing with the lines that you read from the file?
What is the file_object you are passing into get_data_list
My main advice would be to add print everywhere for debugging. See what it stored in your variables at different points in the program and see where a variable doesn't contain what you think it should

Adding a error message in Python as well as commands

#!/usr/bin/env python3
import csv
# a file in the current directory
FILENAME = "contacts.csv"
def write_contacts(contacts):
with open(FILENAME, "w", newline="") as file:
writer = csv.writer(file)
writer.writerows(contacts)
def read_contacts():
contacts = []
with open(FILENAME, newline="") as file:
reader = csv.reader(file)
for row in reader:
contacts.append(row)
return contacts
def list_contacts(contacts):
for i in range (len(contacts)):
contact= contacts[i]
print(str(i+1) +"."+ contact[0])
print()
def view_contact(contacts):
pos = int(input("Number: "))
if not (pos-1)in range(len(contacts)):
print(str(pos) + ' not in list, try again')
view(contacts)
return
contact = []
print(name + email + phone+".\n")
print()
def delete_contact(contacts):
index = int(input("Number: "))
contact = contacts.pop(index -1)
write_contacts(contacts)
print(contact[0]+" was deleted.\n")
def add_contact(contacts):
name=input("Name: ")
email=input("Email: ")
phone=input("Phone number: ")
contact= []
contact.append(name)
contact.append(email)
contacts.append(contact)
write_contacts(contacts)
print(name + " was added.\n")
def display_menu():
print("Contact Manager")
print()
print("COMMAND MENU")
print("list - List all contacts")
print("view - View a contact")
print("add - Add a contact")
print("delete- Delete a contact")
print()
print()
def main():
display_menu()
contacts = read_contacts()
while True:
command = input("Command: ")
if command.lower() == "list":
list_contacts(contacts)
elif command.lower()== "view":
view_contact(contacts)
elif command.lower()== "add":
add_contact(contacts)
elif command.lower()== "delete":
delete_contact(contacts)
break
else:
print("Not a valid command. Please try again.\n")
print("Bye!")
if __name__ == "__main__":
main()
This all my code. I'm trying to figure out how to make the delete and view commands display an error message when the user enters a number that is invalid but it's not working. I'm also trying to view a contact when the user selects a specific number form list which would then display the email name and phone number of that selected number. I'm currently stuck
The errors im getting are
raceback (most recent call last):
, line 93, in
main()
, line 81, in main
view_contact(contacts)
, line 32, in view_contact
view(contacts)
NameError: name 'view' is not defined
I don't think you has a good start with list into cvs using append, anyway is your example.
You can use remove to remove your contact from list, see examples with list: http://www.thegeekstuff.com/2013/06/python-list
when the user select a specific number from list , just read by stepping to the number phone because you add with: name + email + phone.
adding an error message , use: try except finally

finding item in text file during 2nd read

In the beginning of my program, i opened a file with f = open("foods.txt", "r+"). Later I called this method i created
def findFood(food):
foodRegex = re.compile(r'(?P<food>\S+)\s+\-.*')
for line in f.readlines():
print line
duplicateFound = re.search(foodRegex, line)
if duplicateFound.group('food') == food:
return duplicateFound
else:
return False
However I run the method again. But my program doesn't work the way I want it to. Specifically
def build_meal_plan():
number_of_items = int(raw_input("How many items would you like to add to your meal plan? "))
count = 0
while number_of_items > 0:
print count
food = raw_input("Enter in food name: ")
print food
if findFood(food):
servings = int(raw_input("Number of servings: "))
else:
print "Food not found! Try again? (y/n): ",
choice = raw_input()
if choice == 'y' or choice == "yes":
number_of_items += 1
else:
return
However during the 2nd run of my findFood method I cannot locate an item i know exists within the .txt file. I am not sure why I cannot find the same item I found in the text file during the first run. My assumption is that you can only go through a txt file once.
Once you call f.readlines(), you are at the end of the file. To return to the start, so you can go through it again, call f.seek(0):
def findFood(food):
foodRegex = re.compile(r'(?P<food>\S+)\s+\-.*')
for line in f.readlines():
...
f.seek(0)
Alternatively, you can import the contents of the file to a list:
def import_file(filename):
with open(filename) as f:
content = [line.strip() for line in f]
return content
And use that instead of referring back to the file.
def findFood(food, data):
foodRegex = re.compile(r'(?P<food>\S+)\s+\-.*')
for line in data:
...
Then you don't need to worry about returning to the start.

How to assign a Line Number from a text file to a variable?

I am trying to print the variable 'Number' But it come up with a error.
'TypeError: list indices must be integers, not tuple'
I dont understand? What is a tuple and how could i fix this problem?
How do i assign a line number in a text file to a variable?
def CheckDatabase():
print ("====Check Database===== \nA)Would you like to check details? \nB)Check if they are a member?")
TC = input(": ")
if TC == "A" or TC == "a":
NameDetail = input ("Please enter the name you would like to check the details of.\nThis will only work if they are a member\n: ")
with open('Name.txt') as ND:
for number, line in enumerate(ND, 1):
if (str(NameDetail)) in line:
Number = number, line in enumerate(ND, 1)
print ("\nName = ", NameDetail)
A = open("Address.txt", "r")
AData =[line.rstrip() for line in A.readlines()]
print ("Address = ",(AData[Number]))
HN = open("Home Number.txt", "r")
HNData =[line.rstrip() for line in HN.readlines()]
print ("Home Number = ",(HNData[Number]))
MN = open("Mobile Number.txt", "r")
MNData =[line.rstrip() for line in MN.readlines()]
print ("Mobile Number = ",(MNData[Number]))
EAS = open("Email Address.txt", "r")
EAData =[line.rstrip() for line in EAS.readlines()]
print ("Email Address = ",(EAData[Number]))
MDND = open("Email Address.txt", "r")
MDNData =[line.rstrip() for line in MDND.readlines()]
print ("Medical/Dietry Needs = ",(MDNData[Number]))
else:
print ("Person not found!")
EDIT:
import time
def AddToDatabase():
print ("\nYou are adding to the Database. \nA)Continue \nB)Go Back")
ATD = input(": ")
if ATD == "A" or ATD == "a":
Name = input("\nEnter Name of Member [First Name and Surname]: ")
with open("Name.txt", "a") as N:
N.write("\n{}".format(Name))
time.sleep(1)
print ("\nAdding...")
time.sleep(1)
print ("\nEnter Address of "+Name+" all on one line")
print ("In format [Include Commas]")
print ("\nRoad name with house number [e.g. 1 Morgan Way], Borough [e.g Harrow], City [e.g London], Postcode [e.g. HA5 2EF]")
Address = input("\n: ")
with open("Address.txt", "a") as A:
A.write("\n{}".format(Address))
time.sleep(1)
print ("\nAdding...")
time.sleep(1)
Home_Number = input("\nEnter Home Number of "+Name+": ")
with open("Home Number.txt", "a") as HN:
HN.write("\n{}".format(Home_Number))
time.sleep(1)
print ("\nAdding...")
time.sleep(1)
Mobile_Number = input ("\nEnter Mobile Number of "+Name+": ")
with open("Mobile Number.txt", "a") as MN:
MN.write("\n{}".format(Mobile_Number))
time.sleep(1)
print ("\nAdding...")
time.sleep(1)
Email_Address = input ("\nEnter Email Address of "+Name+": ")
with open("Email Address.txt", "a") as EA:
EA.write("\n{}".format(Email_Address))
time.sleep(1)
print ("\nAdding...")
time.sleep(1)
Dietry_Needs = input("\nEnter Medical/Dietry Needs of "+Name+": ")
with open("Medical Dietry Needs.txt", "a") as MDN:
MDN.write("\n{}".format(Dietry_Needs))
time.sleep(1)
print ("\nAdding...")
time.sleep(1)
print ("All information for "+Name+" has been added. Redirecting Back To Main...")
time.sleep(5)
Main()
elif ATD == "B" or ATD == "b":
Main()
def CheckDatabase():
print ("====Check Database===== \nA)Would you like to check details? \nB)Check if they are a member?")
TC = input(": ")
if TC == "A" or TC == "a":
NameDetail = input ("Please enter the name you would like to check the details of.\nThis will only work if they are a member\n: ")
with open('Name.txt') as ND:
for number, line in enumerate(ND, 1):
if (str(NameDetail)) in line:
Number, junk = number, line in enumerate(ND, 1)
print ("\nName = ", NameDetail)
A = open("Address.txt", "r")
AData =[line.rstrip() for line in A.readlines()]
print ("Address = ",(AData[number]))
HN = open("Home Number.txt", "r")
HNData =[line.rstrip() for line in HN.readlines()]
print ("Home Number = ",(HNData[Number]))
MN = open("Mobile Number.txt", "r")
MNData =[line.rstrip() for line in MN.readlines()]
print ("Mobile Number = ",(MNData[Number]))
EAS = open("Email Address.txt", "r")
EAData =[line.rstrip() for line in EAS.readlines()]
print ("Email Address = ",(EAData[Number]))
MDND = open("Email Address.txt", "r")
MDNData =[line.rstrip() for line in MDND.readlines()]
print ("Medical/Dietry Needs = ",(MDNData[Number]))
else:
print ("Person not found!")
elif TC == "B" or TC == "b":
NameChoice = input("Enter persons name: ")
with open('Name.txt') as NAME:
for number, line in enumerate(NAME, 1):
if (str(NameChoice)) in line:
print (NameChoice)
print ("is a member")
else:
print ("Not a member!")
def Main():
print ("\nSVA of UK Database")
while True:
print ("\nA)Check Database \nB)Add to Database \nC)Exit Program")
choice = input(": ")
if choice == "A" or choice == "a":
CheckDatabase()
elif choice == "B" or choice == "b":
AddToDatabase()
elif choice == "C" or choice == "c":
break
else:
print ("Invalid Input")
Main()
Main()
EDIT 2:
Name.txt :
Sagar Bharadia
Address.txt
8 John Road
Home Number.txt
02089563524
Mobile Number.txt
02045745854
Medical Dietry Needs.txt
None
EDIT 3:
SVA of UK Database
A)Check Database
B)Add to Database
C)Exit Program
: A
====Check Database=====
A)Would you like to check details?
B)Check if they are a member?
: A
Please enter the name you would like to check the details of.
This will only work if they are a member
: Sagar Bharadia
Name = Sagar Bharadia
1
Traceback (most recent call last):
File "H:\SVA UK PROGRAM\SVA of UK.py", line 126, in <module>
Main()
File "H:\SVA UK PROGRAM\SVA of UK.py", line 114, in Main
CheckDatabase()
File "H:\SVA UK PROGRAM\SVA of UK.py", line 74, in CheckDatabase
print ("Address = ",(AData[Number]))
IndexError: list index out of range
>>>
You define Number as a tuple when you do Number = number, line in enumerate(ND, 1). You already created number, line in enumerate(ND, 1) with your for loop anyway. Why not just use that? i.e. AData[number].
Just using an example, this is what essentially what you are setting Number to:
>>> for x, y in enumerate([1,2,3], 1):
print x, y in enumerate([1,2,3], 1)
1 False
2 False
3 False
It is a tuple containing the number from your for loop, and the value of line in enumerate(ND, 1) (a boolean expression, either it's in there or it's not).
You also have several other problems:
You start number at 1 instead of 0 by providing the 1 to enumerate. In python, list indices start at 0. So if the length of a list is 1 then sub-indexing at [1] is actually out of bounds. You should be doing enumerate(ND) instead to start at 0.
You need to .close() your files that you open(), or use with/as like you do with your first file.
You are opening Email Address.txt twice... did you mean to do that?
In this line:
Number = number, line in enumerate(ND, 1)
You are assigning two values to Number -- this produces a tuple.
You could do something like this:
Number, junk = number, line in enumerate(ND, 1)
This would result in Number being a single value, no longer a tuple.
Tuples are a kind of a "list". See doc on:
http://docs.python.org/release/1.5.1p1/tut/tuples.html
You are probably assigning 2 or more values for the var Number

Categories

Resources