0

I am getting the following error with my code:

UnboundLocalError: local variable 'row' referenced before assignment

I have tried many things, but nothing has worked. I suspect it is something to do around the 'quantityQuestion' subprogram. According to the scripter, the problem is at line 97.

import csv
import sys

global totalPrice
totalPrice = 0

addItem = ""
gtinNum = ""
quantity = 0
restart = ""

global receipt
receipt = open("receipt.txt", "w+")
global restockTxt
restockTxt = open("restock.txt", "w+")
global price
price = 0
global file2
file2 = open("ChocolateCSV2.csv", "r")
global file2w
file2w = open("ChocolateCSV2.csv", "w", newline="")

def restart():
    restart = input("Would you like to restart? Y/N")

    if restart.lower() == "y":
        actionQ()
    else:
        print("Exiting program.")
        file2.close()
        sys.exit()

def priceSub(): #Defining the restart subprogram
    priceQ = input("Would you like to add an item? Y/N") #Asks the user if they would like to add an item.
    global totalPrice #Declaring totalPrice and making it global.
    totalPrice = int(price) + totalPrice #Setting totalPrice to add the variable price to itself.

    if priceQ.lower() == "y": #If statement that checks to see if the user has entered a "y".
        gtinQuestion() #If it is true, it will start the gtinQuestion subprogram.
    else: #Anything other than a "y" will do the following commands.
        global receiptCont #Declaring the receipt content as a global variable.
        receiptCont = receipt.read() #Reads the receipt.
        receipt.close() #Closes the file.
        print(receiptCont) #Prints the content of the receipt.
        print("Total Price: " + "%.2f" % round(totalPrice, 2)) #Prints the totalPrice variable rounded to two decimal places.
        restart()

def quantityQuestion(): #Defining the subprogram for the quantity.
    quantity = input("How much would you like?") #Asks the user how much of the item they would like.
    if quantity.isdigit() == False: #If statement to check whether or not the user has entered an integer or not.
        quantityQuestion() #If they have not entered an integer, it will ask the question again.
    global price #Declaring the variable price as a global variable.
    price = "" #Setting price to an empty string.

    reader = csv.reader(file2, delimiter = ",")
    csvList = list(reader)

    for row in csvList: #Loop that seperates each row in the CSV
        if str(gtinNum) in row: #If statement to check if the GTIN given by the user is in the CSV.
            receipt.write(str(row) + "\n") #If it is in one of the CSV rows, it will write the row to the text file.
            receipt.write(str("- Quantity: " + quantity + "\n")) #It also writes the quantity given by the user.
            price = float(row[2]) * int(quantity) #The price is the price given by the CSV file multiplied by the quantity.
            receipt.write("- Price: " + str("%.2f" % round(price, 2)) + "\n") #The final price (after the multiplication) is written to the text file also.
            row[2] = row[2] - quantity
            writeCSV = csv.writer(file2w)
            writeCSV.writerow(row)
            file2w.close()
            priceSub() #Starts the restart subprogram.
            break #Breaks the loop.
    else:
            print("The code entered could not be found - Please re-enter") #If it is not in the CSV it will print this error message.
            gtinQuestion() #Starts the gtinQuestion subprogram.

def gtinQuestion(): #Defining the gtinQuestion subprogram.
    global gtinNum #Declaring the gtinNum variable as global.
    gtinNum = input("Please enter the GTIN-8 Code of the product you would like to order:") #Setting that variable to the initial question.

    if gtinNum.isdigit() == False or len(gtinNum) != 8: #If the code given is not an integer or is not 8 digits long...
        print("Please re-enter your GTIN-8 code - Reason: Invalid Code") #It will print this error message and ask the question again.
        gtinQuestion()
    elif gtinNum.isdigit() == True and len(gtinNum) == 8: #If it is an integer and is 8 digits long...
        quantityQuestion() #It will start the quantityQuestion subprogram.

def restockAction():
    reader = csv.reader(file2, delimiter = ",")
    csvList = list(reader)
    for row in csvList:
        stDiff = float(row[5]) - float(row[3])
        if float(row[3]) <= float(row[4]):
            restockTxt.write(row[0]+" | "+row[1]+" | "+"Stock Replenished: "+(str(stDiff)+"\n"))
            restockTxt.close()
            row[3] = row[5]
            writeCSV = csv.writer(file2w)
            writeCSV.writerows(csvList)
            file2w.close()
    else:
            if float(row[3]) >= float(row[4]):
            restockTxt.write("No (other) stock needs to be replenished.")
            restockTxt.close()
            restockRead = open("restock.txt", "r")
            print(restockRead.read())
            restart()


def actionQ():
    restock = input("What action would you like to perform?:\n Restock (Enter 1)\n Order (Enter 2)")

    if restock == "1" or restock == "restock":
        print("Restock Action Requested...")
        restockAction()
    elif restock == "2" or restock == "order":
        print("Ordering action Requested...")
        gtinQuestion()
    else:
        actionQ()

actionQ()

Any help is appreciated,

Thanks.

Jordan
  • 71
  • 1
  • 2
  • 8
  • 1
    Note that `global` definitions do something only when *inside* a function. It's completely useless to add those definitions for definitions at the top level of a module. – Bakuriu Jun 26 '16 at 18:49
  • Did you try to catch the error with a ```try/except``` block and print out the relavent variables (```file2```, ```reader```,```csvList```) to see what is going on? – wwii Jun 26 '16 at 18:55
  • @wwii I think i have solved it. I just removed the whole `if` statement under the else. I did not have to move anything. Now my problem is that when there is a row that needs to be 'restocked' it deletes all the values in the CSV which is quite frustrating. – Jordan Jun 26 '16 at 19:00

2 Answers2

1

The problem is in restockAction():

for row in csvList:
    # some code
else:
    if float(row[3]) >= float(row[4]):
#             ^ 

If there are no rows in csvList, row will not have any value, since the for will not be executed, but the else block will be executed.

So row in the else block of the for has yet to defined.

Did you intend to attach the else to the if, not the for:

for row in csvList:
    stDiff = float(row[5]) - float(row[3])
    if float(row[3]) <= float(row[4]):
        # ...
    else:
        # ...
Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
0

You have to verify you have that you have any rows before checking whether row[index] has a value:

else:
    if row and float(row[3]) >= float(row[4]):
        restockTxt.write("No (other) stock needs to be replenished.")
        restockTxt.close()
        restockRead = open("restock.txt", "r")
        print(restockRead.read())
        restart()

if row and ... acts as a vanguard, protecting the interpreter from executing row[index]. If row is None, if row == False and it returns immediately without evaluating the rest of the statement.

TemporalWolf
  • 7,727
  • 1
  • 30
  • 50