Input Validation in Python - python

So my friend and I have been working on this problem for a few days now for our Intro to Python class at our college, but we are a bit stuck due to the fact we didn't spend much time on this topic in class. Our problem is this, "Every product ID must be six characters long and starts with three upper case letters followed by three digits. For example ABE123 and PPL334 are valid product IDs but ABE1.2 and P1L3R4 are not. The auction site has a minimum bid price of 5 dollars and caps bids at 500 dollars. Bids with dollars and cents are acceptable. For example 6.78 is a valid bid. The following code reads in bids from the prompt (keyboard inputs) and loads the product ids and bidding prices into two lists products and bids. Unfortunately the code contains no input validation which is your job to complete." Our teacher gave us the code, we just have to validate the inputs. But it has to be done outside of her code, as in its own function. Here is the code:
`def getbids():
products = []
bids = []
answer = "yes"
while answer == "yes":
productid = input("Enter the productID ")
bid = float(input("Enter the bid for one item "))
products.append(productid)
bids.append(bid)
answer = input("Are there more bids? ")
return products, bids`
Basically, our job is to validate the productid and the bid in separate functions. I have our code here but what we have doesn't work completely and is not correct.
Here is the one for productId:
`def validprod(n):
caps="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
nums="0123456789"
m="Error"
if len(n)!=6:
print("Error, productID must be 6 digits,3 capital letters followed by 3 numbers")
return m
else:
while len(n)==6:
for i in range(3):
if n[i] not in caps or n[i+3] not in nums:
print("Error, productID must be 6 digits,3 capital letters followed by 3 numbers")
return m
else:
return n`
Here is the one for bids:
`def validbid(x,y):
bid="Error"
while x=="Error":
return bid
while x!="Error":
if y>500 or y<5:
print("Error, bid must be between 5 and 500(do not include a dollar sign with your bid).")
return bid
else:
return y`
We know there is probably a much simpler way to do it, we just don't know it.

import re
pid_regex = re.compile(r'^[A-Za-z]{3}\d{3}$')
def is_valid_pid(pid):
if pid_regex.match(pid):
return True
return False
def is_valid_bid(bid):
return bid >= 5 and bid <= 500
def getbids():
products = []
bids = []
answer = "yes"
while answer == "yes":
productid = input("Enter the productID ")
products.append(productid)
bid = float(input("Enter the bid for one item "))
bids.append(bid)
answer = input("Are there more bids? ")
return products, bids
products = dict(zip(*getbids()))
for pid in products:
bid = products[pid]
if not is_valid_pid(pid):
print('PID {} is invalid.'.format(pid))
break
elif not is_valid_bid(bid):
print('PID {} has an invalid bid {}'.format(pid, bid))
break
else:
print('PID {} to bid {} seems OK.'.format(pid, bid))
Note: I needed to fix your getbids() function, because products were not being appended to the products list.
Another note: If you believe I was wrong to provide a complete solution, please let me know. I'm completely open to feedback from the public.

Related

Rounds integer even with float- python

Below is my code. the issue is in MAIN. The code works as a person trying to buy items into a cart and you can see the total price of those items. They have to enter in the price for each item that they want. If a person inputs a number to two decimal places, it rounds it to the nearest whole number.
import locale
class CashRegister:
def __init__(self):
mself.items = 0
self.price = int(float(0.00))
def addItems(self,price): #keeps track of total number of items in cart
self.price += price
self.items += 1
print(self.price)
def getTotal(self): #returns total price
return self.price
def getCount(self): #return the item count of the cart
return self.items
def clearCart(self): #clears cart for another user or checkout
self.items = 0
self.price = int(float(0.00))
def main():
user_name = input('What is your name?\n') #weclomes user
print("Hello",user_name)
locale.setlocale(locale.LC_ALL, 'en_US')
user_name = CashRegister() #user is using the cash register
while True:
line = input ("Would you like to add another food item to your cart? Choose y or n \n")
if line == "y":
** price = int(float(input("please input the price of the item\n")))
print(price)**
user_name.addItems(price) #user adds prices to cart
elif line == "n":
print("Your total checkout price:", locale.currency(user_name.getTotal()) )
# int(float(locale.currency(user_name.getTotal())))
print("Your total item count", user_name.getCount())
user_name.clearCart() #clears cart for another user/checkout
break
else:
print("Error")
if __name__ == '__main__':
main()
As soon as the person inputs the number, I printed it to see if that's where the problems lies. I'll enter 3.20 but it automatically converts it to 3. I have no idea how to force it to keep those decimals. I even tried printing it with the int/float and it still doesn't work.
The int() function always returns an integer. An integer never has any decimal points. So use only
float(input("please input the price of the item\n"))
instead of
int(float(input("please input the price of the item\n")))

Shopping List Program

I am coding a program that simulates someone making a purchase in a grocery store. I am displaying all the products and the price and I am prompting the user to input all the products they went to buy separated by commas. I want the program to check if the input is in the dictionary of product and add it to the cart with the use of a loop. Before adding it to cart the program needs to check if the input is valid, meaning if the item is in the list of products to buy. When the user selects an item to buy, I want the program to ask the user for the quantity of that item, so how many of the item they want to buy. At the samThen the program will calculate the total of all the products, then calculate the tax value, 24% of the total, and then return a subtotal that includes tax. Here is what I have so far:
def calculatetotal(slist, produce):
# for each item on the shoping list look up the cost & calculate total price
item_price = 0
subtotal = 0
VAT = 0
final_total = 0
basket = {}
for item in slist:
item_price = produce.get(item)
basket[item] = item_price
subtotal = subtotal + item_price
basket["Subtotal"] = subtotal
#calculating VAT
VAT = subtotal * 0.24
basket["VAT"] = VAT
#calculating price with tax
final_total = subtotal + VAT
basket["Total"] = final_total
# print off results
return basket
def main():
# set up grocery list with prices
produce={"Rice":5.00, "Bread":2.00, "Sugar":1.5, "Apple":0.75, "Cereal":3.75, "Gum": 1.00, "Water": 1.75, "Soda": 2.00}
# process input from the user - get a shopping list
item = input("Please enter the items that you want to buy: ")
slist = []
while(item != 'stop'):
if not (item in slist):
slist.append(item)
item = input("Please enter the items that you want to buy: ")
result = calculatetotal(slist, produce)
print(result)
main()
I've gotten most of it, but the small changes that I mentioned above, I can't figure out what to do. I forgot to mention that asking for the quantity of the item and checking if the user input has to be done with a loop. Any input is very much appreciated. Please show the change of code. Thank you in advance.
In this case I would simply go for a while loop
while True:
item = input("Please enter the items that you want to buy: ")
if item == 'Stop':
break
elif item not in produce or item in slist:
# error message or whatever
else:
num = int(input("Enter Quantity"))
# other operations

Print a receipt in Python that doesn't repeat the items

I need to create a function that creates a session that accepts a "clerk's" input data about a customer's orders until the "clerk" enters the string "/". Each line of input consists of two elements: the product code and the quantity. Lines of input are formatted as follows: "{product_code},{quantity}". The function should write a file called receipt.txt that prints a summarized report of the session.
The receipt should provide a summary of all the orders made during the session and the product must only appear once if it has been ordered at least once during the session, even if it has been ordered multiple times. In other words, if a product is ordered multiple times, then it should only have one entry in the receipt that describes the sum of all of the orders made for that product. The products must appear in alphabetical order.
Here is my code right now and it prints a receipt but I don't know how to make the order appear only once and make it alphabetical order. Please help.
EDIT: Added get_property function.
def get_property(code,property):
return products[code][property]
def main():
products = {
"americano":{"name":"Americano","price":150.00},
"brewedcoffee":{"name":"Brewed Coffee","price":110.00},
"cappuccino":{"name":"Cappuccino","price":170.00},
"dalgona":{"name":"Dalgona","price":170.00},
"espresso":{"name":"Espresso","price":140.00},
"frappuccino":{"name":"Frappuccino","price":170.00},
}
orders_list = []
total = 0
while(True):
customer_order = input("Welcome to the CoffeePython POS Terminal.\nPlease enter the Product Code and the Quantity in this format - {Product Code},{Quantity}.\nEnter '/' to quit.\n")
if customer_order == "/":
break
else:
code_quantity_list = customer_order.split(",")
code = code_quantity_list[0]
quantity = code_quantity_list[1]
quantity_int = int(quantity)
if code in products:
subtotal = get_property(code,"price")*quantity_int
total += subtotal
ordered_item = dict([
('code', code),
('qty', quantity_int),
('subtotal', subtotal)
])
orders_list.append(ordered_item)
else:
print("The Product Code that you entered is invalid. Please try again.")
print("==")
print("CODE\t\t\tNAME\t\t\tQUANTITY\t\t\tSUBTOTAL")
for order in orders_list:
order_code = order['code']
order_name = products[order_code]["name"]
order_qty = order['qty']
order_subtotal = order['subtotal']
print(f"{order_code}\t\t{order_name}\t\t{order_qty}\t\t\t\t{order_subtotal}\t\t")
print(f"\nTotal:\t\t\t\t\t\t\t\t\t\t{total}")
print("==")
print("Thank you for ordering. Goodbye.")
main()
Output
==
CODE NAME QUANTITY SUBTOTAL
americano Americano 2 300.0
americano Americano 2 300.0
Total: 600.0
==
To store the orders, I would suggest you to use a dictionary with code as a key, and the price as value.
orders_list = {}
while ...:
orders_list[code] = orders_list.setdefault(code, 0) + subtotal
for product in sorted(orders_list):
subtotal = orders_list[product]
print(f"{product:<10} {subtotal}")
You need to check the saved list in orders_list and then evaluate the existing key. For sort list in the order_list by key in a dict, you can use this reference
How do I sort a list of dictionaries by a value of the dictionary?
I am adding a new method to perform check.
Also, I am not sure about your get_property() method, I changed it a bit.
def check_code(orders_list, code):
codes = []
for i in orders_list:
codes.append(i["code"])
if(code in codes):
return True, codes.index(code)
else:
return False, 0
def main():
products = {
"americano":{"name":"Americano","price":150.00},
"brewedcoffee":{"name":"Brewed Coffee","price":110.00},
"cappuccino":{"name":"Cappuccino","price":170.00},
"dalgona":{"name":"Dalgona","price":170.00},
"espresso":{"name":"Espresso","price":140.00},
"frappuccino":{"name":"Frappuccino","price":170.00},
}
orders_list = []
total = 0
while(True):
customer_order = input("Welcome to the CoffeePython POS Terminal.\nPlease enter the Product Code and the Quantity in this format - {Product Code},{Quantity}.\nEnter '/' to quit.\n")
if customer_order == "/":
break
else:
code_quantity_list = customer_order.split(",")
code = code_quantity_list[0]
quantity = code_quantity_list[1]
quantity_int = int(quantity)
if code in products:
# subtotal = get_property(code,"price")*quantity_int
subtotal = products[code]["price"] *quantity_int
check = check_code(orders_list, code)
if check[0]:
orders_list[check[1]]["subtotal"] += subtotal
orders_list[check[1]]["qty"] += quantity_int
else:
ordered_item = dict([
('code', code),
('qty', quantity_int),
('subtotal', subtotal)
])
orders_list.append(ordered_item)
total += subtotal
else:
print("The Product Code that you entered is invalid. Please try again.")
print("==")
print("CODE\t\t\tNAME\t\t\tQUANTITY\t\t\tSUBTOTAL")
orders_list = sorted(orders_list, key=lambda k: k['code'])
for order in orders_list:
order_code = order['code']
order_name = products[order_code]["name"]
order_qty = order['qty']
order_subtotal = order['subtotal']
print(f"{order_code}\t\t{order_name}\t\t{order_qty}\t\t\t\t{order_subtotal}\t\t")
print(f"\nTotal:\t\t\t\t\t\t\t\t\t\t{total}")
print("==")
print("Thank you for ordering. Goodbye.")
main()
When i test the code the item prints once and i did following:
frappuccino, 1
americano, 2
dalgona, 1
So i cannot reproduce the issue but i dont have the get_properties method either so maybe thats the issue.
As for printing the list in alphabetical order you should look to sort the list before looping and printing the reciept. You will find how you can achieve sort on a list containing dictionaries
here

Checking if inputted strings are equal to strings in list?

I'm working on a project that involves building a simplified version of a calendar agent that asks the user for when they want to schedule an appointment and does it for them (if that slot is free). This is the code I have so far:
def find_index(val, seq):
for index in range(len(seq)):
place = seq[index]
if place == val:
return index
else:
return int("-1")
def find_val(val, seq):
for ele in seq:
if val == ele:
return True
else:
return False
def init_nested_list(size_outer, size_inner):
cal = []
for outer_index in range(size_outer):
nested_list = []
for inner_index in range(size_inner):
nested_list.append("-")
cal.append(nested_list)
return cal
def get_input(possible_vals, day_or_time_string):
count = 0
if day_or_time_string == "day":
answer = input("What day would you like your appointment? ")
else:
answer = input("What time would you like your appointment? ")
answer = answer.strip()
nested_list = find_val(answer, possible_vals)
while answer in possible_vals:
break
else:
count = count + 1
answer = input("Invalid entry. Please enter a valid day: ")
if count == 3:
print("This is getting silly - still not a valid entry")
answer = input("Please do try to enter a valid day: ")
count = 0
return answer
def book_slot(cal,days_labels, times_labels, day, time): **ignore this function, haven't finished it yet**
find_index(day, days_labels)
def start_scheduler(cal, days_labels, times_labels):
while True:
day = get_input(days_labels, "day")
time = get_input(times_labels, "time")
book_slot( cal, days_labels, times_labels, day, time)
print("--------------------------------- ")
res = input("Did you want to book more appointments (type n for no, any other key for yes)? ")
if res == "n":
break
days_labels= ["Monday","Tuesday","Wednesday","Thursday", "Friday"]
times_labels = ["9","10","11","12","1","2","3","4","5"]
calendar = init_nested_list(len(days_labels), len(times_labels))
print("Welcome to the acupuncture booking system. ")
start_scheduler(calendar, days_labels, times_labels)
This is what the complete output should look like so far:
Welcome to the acupuncture booking system.
What day would you like your appointment? saturday
Invalid entry. Please enter a valid day: Monday
What time would you like your appointment? 24
Invalid entry. Please enter a valid time: 9
---------------------------------
Did you want to book more appointments (type n for no, any other key for yes)?
However, it seems that no matter what I input when the function asks me for the date/time of the appointment, it doesn't check to see if the inputted strings are equivalent to any of the acceptable ones (in the lists days_labels and times labels). Instead it just accepts any second random input to be correct as shown:
Welcome to the acupuncture booking system.
What day would you like your appointment? s
Invalid entry. Please enter a valid day: z
What time would you like your appointment? d
Invalid entry. Please enter a valid day: f
---------------------------------
Did you want to book more appointments (type n for no, any other key for yes)?
What needs to be done in order to have the function check to see if the inputted strings correspond with any of the strings in the days_labels and times_labels lists in order for the user to "book" an appointment?
So you wont to create a function to check if any inputted string have been already used.
There reason your code isnt working correctly is because you tried to check wherethere your counter is up to 3, while it isnt any loop, and thus it only ascends to 1.
To re-arrange that to a correct way for example, you would do this:
while answer not in possible_values:
<your code here>
I didn't test this at all but it should be enough to guide you to fix your incrementing error.
def isValidDayInput(input):
accept = false
# your code here
return accept
def dayInput(count, maxAttempts):
waiting = true
while (waiting && count <= maxAttempts):
answer = promptForInput()
if (isValidDayInput(answer)): # accept returned true during validation
waiting = false # answer is valid so jump out loop
else(): # accept returned false during validation
count += 1
if (!waiting && count == maxAttempts):
print("Too many incorrect attempts. Exit")
else:
print("thank you")

str reset to 0 when not asked to?

I am trying to print the total of the shopping list but every time i call on the string it prints 0 instead of what it should be.
cash_due = 0
import pickle
picklee = open('Store_stuff.pickle', 'rb')
contents = pickle.load(picklee)
picklee.close()
shopping_list = ['Name price quantity total']
store_contents ='''Store Contents
Name Price GTIN-8 Code
Butter £1.20 70925647
Chocolate £1.00 11826975
Bread £1.00 59217367
Cheese £2.80 98512508
Bacon £2.40 92647640
Lamb £4.80 49811230
Ham £2.59 53261496
Potatoes £2.00 11356288
Chicken £3.40 89847268
Eggs £1.29 21271243'''
def item(barcode, quantity, cash_due, shopping_list):
shopping_list.append(contents[barcode]['name']+' £'+(str((int(contents[barcode]['price']))/100))+' '+str(quantity)+' £'+str((int(quantity)*int(contents[barcode]['price']))/100))
print(cash_due)
print(contents[barcode]['price'])
print(quantity)
cash_due += ((int(contents[barcode]['price'])*(int(quantity)))/100)
print(cash_due)
def shopkeeper_ui():
print('Welcome to Stanmore\'s Food Emporium! Feel free to browse.')
print(store_contents)
user_input = ''
while user_input != 'finish':
user_input = input('''Welcome to the checkout.
instructions -
if you are entering text make sure your \'CAP\'s Lock\' is turned off
if you are entering a barcode number, please enter it carefully
if you want to print your current recipt, enter \'recipt\'
if you want to see your current total, enter \'total\'
and if you are finished, enter \'finish\'
You can see the stores contents below
Thanks for shopping: ''')
if len(user_input) == 8:
quantity = int(input('Enter the quantity that you want: '))
item(user_input, quantity, cash_due, shopping_list)
elif user_input == 'recipt':
count8 = 0
for i in shopping_list:
print(shopping_list[count8])
count8 += 1
elif user_input == 'finish':
print('Your shopping list is',shopping_list,' \nand your total was', total,'\n Thank you for shopping with Stanmore\'s Food Emporium')
elif user_input == 'total':
print('your total is, £',cash_due)
else:
print('User_input not valid. Try again...')
shopkeeper_ui()
If i enter the code and my first entry is 21271243 (the barcode for eggs). then i enter 4 for the quantity. i can get the shopping_list list to understand the total and if I print the string cash_due from inside the item function it understands it but as soon as i try to call cash_due from the shopkeeper_ui function it prints 0 instead of what should be 5.12?
cash_due is not mutable. Changes in item function are lost when leaving the function.
Generally, the way out of this is to let the function (item) return the value.
In this case, I would just keep cash_due out of item function and let item only return the cost for that item. Something like this:
def item(barcode, quantity, shopping_list):
shopping_list.append(contents[barcode]['name']+' £'+(str((int(contents[barcode]['price']))/100))+' '+str(quantity)+' £'+str((int(quantity)*int(contents[barcode]['price']))/100))
print(contents[barcode]['price'])
print(quantity)
cost = ((int(contents[barcode]['price'])*(int(quantity)))/100)
print(cost)
return cost
[...]
if len(user_input) == 8:
quantity = int(input('Enter the quantity that you want: '))
cash_due += item(user_input, quantity, shopping_list)
You don't have the same issue with shopping_list because it is a mutable: it is changed in place. Read about mutables to understand the concept.
However, it could be better design to not let item modify the list. It could just return both the list element and the cost, and the caller would modify the list.
def item(barcode, quantity):
stuff = (contents[barcode]['name']+' £'+(str((int(contents[barcode]['price']))/100))+' '+str(quantity)+' £'+str((int(quantity)*int(contents[barcode]['price']))/100))
cost = ((int(contents[barcode]['price'])*(int(quantity)))/100)
return stuff, cost
[...]
if len(user_input) == 8:
quantity = int(input('Enter the quantity that you want: '))
stuff, cost = item(user_input, quantity, shopping_list)
shopping_list.append(stuff)
cash_due += cost

Categories