pythoncsv

How can I delete a row from a csv file?


enter image description here enter image description here

When I try to delete a row from my csv file, it deletes everything else and then turns that row sideways and separates the characters into their own columns. I have no idea what is happening. Above are pictures that show the before and after of my csv file when I try to delete. I have no idea what is happening and it is super strange. Here is my code and the issue is on line 95:

import csv
import sys

FILENAME = "guests.csv"

def exit_program():
    print("Terminating program.")
    sys.exit()

def read_guests():
    try:
        guests = []
        with open(FILENAME, newline="") as file:
            reader = csv.reader(file)
            for row in reader:
                guests.append(row)
        return guests
    except FileNotFoundError as e:
##        print(f"Could not find {FILENAME} file.")
##        exit_program()
        return guests
    except Exception as e:
        print(type(e), e)
        exit_program()

def write_guests(guests):
    try:
        with open(FILENAME, "w", newline="") as file:
##            raise BlockingIOError("Error raised for testing.")
            writer = csv.writer(file)
            writer.writerows(guests)
    except OSError as e:
        print(type(e), e)
        exit_program()
    except Exception as e:
        print(type(e), e)
        exit_program()

def list_guests(guests):
    number_of_guests = 0
    number_of_members = 0
    total_fee = 0
    for i, guests in enumerate(guests, start=1):
        print(f"{i}. Name:        {guests[0]} {guests[1]}\n   Meal:        {guests[2]} \n   Guest Type:  {guests[3]} \n   Amount due:  ${guests[4]}")
        if guests[3] == "guest":
            number_of_guests +=1
        if guests[3] == "member":
            number_of_members +=1
        total_fee += 22
              
    print("Number of members: " +str(number_of_members))
    print("Number of guests: " +str(number_of_guests))
    print("Total fee paid by all attendees: " +str(total_fee))
    print()
    
def add_guests(guests):
    fname = input("First name: ")
    lname = input("Last name: ")
    while True:
        try:
            meal = str(input("Meal(chicken, vegetarian, or beef): "))
        except ValueError:
            print("Please enter a meal. Please try again.")
            continue
        if meal == "beef" :
            break
        if meal == "chicken" :
            break
        if meal == "vegetarian" :
            break
        else:
            print("Please enter a meal:(chicken, vegetarian, or beef)")

    while True:
        attendee_type = input("Are you a 'member' or 'guest'?")
        if attendee_type == "member" :
            break
        if attendee_type == "guest" :
            break
        else:
            print("Please enter either 'member' or 'guest': ")
    fee = 22
    
    
    guest = [fname, lname, meal, attendee_type, fee]
    guests.append(guest)
    write_guests(guests)
    print(f"{fname} was added.\n")

def delete_guest(guests):

    name = input("Enter the guest's first name: ")
    for i, guests in enumerate(guests, start=1):
        if name == guests[0]:
            del guests[i]

            write_guests(guests)
                
            print(f"{name} removed from catalog.")
            print("")
            break
    print(f"{name} doesn't exist in the list.")

def menu_report(guests):
    number_of_beef = 0
    number_of_chicken = 0
    number_of_vegetarian = 0
    for i, guests in enumerate(guests, start=1):
        if guests[2] == "beef":
            number_of_beef +=1
        if guests[2] == "chicken":
            number_of_chicken +=1
        if guests[2] == "vegetarian":
            number_of_vegetarian +=1
              
    print("Number of Chicken entrees: " +str(number_of_chicken))
    print("Number of Beef entrees: " +str(number_of_beef))
    print("Number of vegetarian Meals: " +str(number_of_vegetarian))
    print()

def display_menu():
    print("COMMAND MENU")
    print("list - List all guests")
    print("add -  Add a guest")
    print("del -  Delete a guest")
    print("menu - Report menu items")
    print("exit - Exit program")
    print()    

def main():
    print("The Guests List program")
    print("")
    guests = read_guests()
    while True:
        display_menu()
        command = input("Command: ")
        if command.lower() == "list":
            list_guests(guests)
        elif command.lower() == "add":
            add_guests(guests)
        elif command.lower() == "del":
            delete_guest(guests)
        elif command.lower() == "menu":
            menu_report(guests)
        elif command.lower() == "exit":
            break
        else:
            print("Not a valid command. Please try again.\n")
    print("Bye!")
    quit()

if __name__ == "__main__":
    main()

I thought it would delete the row but instead it saved only that row and made each entry in a column of that row into it's on row. each character in the original row was now separated into it's own column.


Solution

  • Avoid shadowing

    Use singular and plural identifiers where appropriate. The usual idiom is
    for x in xs:

    You wrote:

    for i, guests in enumerate(guests, start=1):
        if name == guests[0]:
            del guests[i]
    

    What you wanted to write was for i, guest in ...

    When testing name equality, you intended to refer to guest[0], the first column of a row.

    Regrettably the new guests local variable is shadowing the original guests parameter. As a result, that parameter is no longer accessible within the loop body.

    Mutate outside the loop

    I recommend conditionally assigning match_index = i inside the loop, and then issuing del guests[match_index] after the for loop has finished.

    Also, it's too bad the program doesn't verify that each guest name is unique.

    If you wish to filter on a non-unique attribute, such as removing guests having "beef", then consider building a new filtered list, and returning that. This avoids skipping rows that might match.

    Normalize first

    command = input("Command: ")
    

    Better to downcase that immediately.

    command = input("Command: ").lower()
    

    Then you can save a bunch of distracting .lower() calls in the subsequent dispatch tests.