CS303E Project 3

Instructor: Dr. Bill Young
Due Date: Wednesday, April 24, 2023 at 11:59pm

The Assignment: Building an Online Shopping Utility

A lot of shopping these days is done online, even shopping for food. The large grocery chain H.E.B., for example, has an online shopping app that allows you to order food, which can either be delivered to your home or picked up at the store. Typically this implies an online database of products; the user browses the selections and adds them to a virtual shopping cart.

In this assignment, you will build such an application. There is a csv (comma-separated values) file here Cheeses.csv containing information about various cheese products offered by H.E.B. You will read lines from this file to populate your database. Each line has form: company, description, price. Here are some sample lines from the file:

American Accent,Sandwich Cheese Slices; 16 ct,1.53
Babybel,Mini Plant-Based Cheese Alternative - White Cheddar; 6 ct,4.66
Borden,American Cheese Singles; Fat Free; 16 ct,3.11
CABOT,Fiery Jack Shredded Cheese Blend; 8 oz,3.42
Every line should have two commas. Everything before the first comma is the company name; it may be one or several words. (BTW: "brand" and "company" really mean the same thing here.) Everything between the commas is the product description, which can be arbitrarily complex. Following the second comma is the price, which is of the form "dollars.cents".

Whenever you display a price, display it to two decimal places.

I don't think there are any ill-formed lines; please let me know if I'm wrong about that. Ignore any lines that begin with "#"; these are comment lines. Again, I don't believe there are an "#" characters that are not at the beginning of a line. Lines are in alphabetical order, but that is not really relevant for this project. All searches are linear.

Part 1 of the assignment is to read lines from this file and use the information to populate a product database. The 'database' is a dictionary mapping the product's Sku ("stock keeping unit": a unique identifying number assigned to each product) to a product object, one for each (non-comment) line in the file.

You'll use each product description in the file to create an object in a user-defined Product class. An object of this class contains the fields: Sku (integer), company (string), description (string), price (float). All fields should be private. All fields but Sku come from a line in the file. The Sku is just a counter, starting at 1 and incremented for each successive product (non-comment line). Add the newly created object to the database dictionary with the Sku as key. Notice that the product Sku is stored redundantly, both as the key in the dictionary and in the product object (value) in the dictionary; we could probably get around this, but it makes life a bit easier. You should also define the __str__ method to print an instance of the product. See the examples in the sample output below.

Part 2 of this assignment is to implement a command interface for querying the database and adding/removing items from an online shopping cart. Your interface should support the following commands:

   Help     - show available commands;
   Exit     - exit the application, without purchasing anything;
   Brands   - list the brands/companies available;
   Search   - display products matching the brand and/or description keywords;
   Add      - add a product to your shopping cart by Sku number;
   Remove   - remove a product from your shopping cart by Sku number;
   Cart     - display the current contents of your shopping cart;
   Checkout - display a customer "receipt" from purchasing the contents of the shopping cart.
Both the Help and Brands commands just involve printing a long string. See the samples below.

When searching, you'll ask the user to specify a brand and keywords related to the product. Either or both can be omitted (by hitting the return/enter key). A value of return means to allow any match. Your interface should not be case sensitive.

The behavior of each command is illustrated in the sample output below. Here is a more detailed description of how each of these commands should work:

The Help command prints a list of the available commands. This is just printing a long string to the terminal. You don't need to collect this list when reading, or scrape them from the database.

For Exit, print a Goodbye message and exit the program without purchasing anything. (In my version, I also allowed Quit to work the same way, but didn't advertise that in the help message. You don't have to do this, but can if you like. See a further discussion in the Programming Tips section below.)

The Brands command displays the available brands. This is useful since someone looking for, say, cheddar cheese may not realize which brands are available to order. Like Help this just involves printing a message.

Search is the most complicated command. Search allows the user to specify a Brand and/or Product keywords. For either of these, you can hit return/enter, which means to match any brand and/or product. For example, if the user hits return for both prompts, the entire list of products should be displayed. The response to Brand, if any is given, is a string which matches a brand if it appears anywhere in a brand name. E.g., "Hill" matches "Hill Country Fare" but also "Kate Hill." And "he" matches "HEB" but also "Follow Your Heart" and "Frigo CheeseHeads." Notice that case doesn't matter; so just lowercase before you make the comparison.

The response to Product keywords, if given, is a whitespace separated sequence of words. A product matches if all keywords appear as substrings anywhere within that product's description. For example,

Enter a command (help, quit, brands, search, add, remove, cart, checkout): search

  Brand (or return for any brand): 
  Product keywords (or return for any): ricot whole

Found the following matching products:
  46:  $5.71 Galbani Classic Whole Milk Ricotta Cheese ; 28 oz
  47:  $4.67 Galbani Lactose Free Whole Milk Ricotta Cheese; 15 oz
This means to search for products of any brand with a description containing strings "ricot" and "whole" (where case doesn't matter). In the database there are only two matches, both from Galbani.

As another example,

Enter a command (help, quit, brands, search, add, remove, cart, checkout): search

  Brand (or return for any brand): hill
  Product keywords (or return for any): cream

Found the following matching products:
  274:  $1.45 Hill Country Fare Neufchatel Cream Cheese; 8 oz
  284:  $6.13 Kite Hill Almond Milk Chive Cream Cheese; 8 oz
  285:  $6.13 Kite Hill Dairy Free Almond Milk Plain Cream Cheese; 8 oz
matches any brand containing the string "hill" and any product description containing the string "cream." A blank is just another character, so "te h" would match "Kite Hill".

Note that there's a subtle difference between how the Brand and Product keywords are treated. The string specified for brand, if any, is a single string that must be found exactly (except for case) somewhere inside the product's brand/company name for there to be a match. The product keywords, if any, are multiple whitespace-separated strings, all of which must be found exactly (except for case) within the product's description to have a match.

The Add command adds a product to the user's shopping cart (which is just a list, initially empty, of product objects). The user is prompted for the product Sku. If the Sku isn't a key in the database, print "No product with Sku <Sku> found" where <Sku> is the number entered. You can assume that the Sku supplied is an integer. Here's an example:

Enter a command (help, quit, brands, search, add, remove, cart, checkout): add

  Enter product Sku to add to cart: 284

Enter a command (help, quit, brands, search, add, remove, cart, checkout): add

  Enter product Sku to add to cart: 1000

No product with Sku 1000 found.
Displaying the contents of the cart with command cart will show that product 284 has been added to the cart. Items must be added one at a time; there's no provision to add, say, three of product 284. Notice that we also don't allow specifying the Sku in the command, e.g., add 284; that would be a good extension to the assignment, but I didn't do it in mine, and you shouldn't either.

The Remove command is similar to Add except that it removes the product with given Sku from the cart. If the Sku doesn't match an item in the customer's card, print "No product with Sku <Sku> found." where <Sku> is the Sku number provided by the customer.

The Cart command displays the current contents of the user's shopping cart along with a summary listing the number of items and the total cost. Items are listed in the order in which they were added to the cart.

Enter a command (help, quit, brands, search, add, remove, cart, checkout): cart

Your shopping cart contains:
  284:  $6.13 Kite Hill Almond Milk Chive Cream Cheese; 8 oz
  274:  $1.45 Hill Country Fare Neufchatel Cream Cheese; 8 oz
  47:  $4.67 Galbani Lactose Free Whole Milk Ricotta Cheese; 15 oz
Cart contains 3 items, for a total cost of $12.25

The Checkout command causes the current contents of the cart to be displayed along with a summary. Then the goodbye message is displayed. It is similar to a combination of Cart and Exit but the message is slightly different. For example:

Enter a command (help, exit, brands, search, add, remove, cart, checkout): checkout

You have purchased the following items:
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
  380:  $5.14 SARGENTO Light Reduced Fat Low Moisture Mozzarella String Cheese; 12 ct
  361:  $4.14 Philadelphia Blueberry Cream Cheese; 7.5 oz
Summary: 3 items for a total cost of $13.42

Thanks for shopping with us! Please come back soon.
If the command is none of the above, print an error message and return to the command loop.

The Algorithm:

Don't attempt to do this entire assignment at once; break it into pieces and test each thoroughly before going on to the next one. Perhaps create a version of the input file with only 10 lines for testing.

Here is a suggestion of some steps to carry out this assignment.

  1. Write a separate function that reads lines from the input file and creates and returns the product database.
    1. The Sku counter is initially 1.
    2. Assume for this function that the input file exists. You'll check that in the main function.
    3. Read a line from the file; if it starts with '#' discard it. Otherwise, parse it into its fields using split(",").
    4. Extract the fields we need: company, description, price. Remember that these will be strings. Convert the price to a float.
    5. Create a product object with those fields and the Sku. Add to the database (dictionary) using the Sku as the key.
    6. Increment the Sku.
    7. Repeat the steps above for all lines in the file.
    8. Return the resulting dictionary; this is the database you'll use for the shopping application.
    9. Test this function thoroughly before moving on.
    10. In particular, test that you can access an item from the database by Sku and print it; the format should match what's in the sample output.

  2. Now you'll build the query processing functionality. This will be your main function.
    1. Check that the input file exists; if not, exit after printing an error message: Cannot find file: and the filename.
    2. From the input file, build your database (dictionary), and print a line saying that you are doing so.
    3. Print the welcome message.
    4. Enter a loop to accept commands from the user, parse them and process them. Remember that case doesn't matter for the commands, including brand names and product descriptions.
    5. Individual commands should be handled as described above.
    6. Add and test a command at a time.
Then congratulate yourself because you're writing some pretty sophisticated code that you probably couldn't have imagined writing when you started this semester!

Sample Behavior:

> python Project3.py
Enter data filename: arglebargle.csv
Cannot find file: arglebargle.csv
> python Project3.py
Enter data filename: Cheeses.csv
Creating product database from file: Cheeses.csv

Welcome to the online shopping app. We have a large selection of cheeses
available from many popular brands. Happy shopping!

Enter a command (help, exit, brands, search, add, remove, cart, checkout): help

The following commands are available:
   Help      - show this message;
   Exit      - exit this application;
   Brands    - list the brands available;
   Search    - look for products by brand and/or by description keywords;
   Add       - add a product to your shopping cart by Sku number;
   Remove    - remove a product from your shopping cart by Sku number;
   Cart      - display the current contents of your shopping cart;
   Checkout  - purchase the contents of your shopping cart.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): brands

We have cheeses available from all of the following brands:
   American Accent, Babybel, Borden, Cabot, Crystal Farms Dairy,
   Cacique, Cafe Olympia, Daiya, Disney, Follow Your Heart, Frigo
   CheeseHeads, HEB, Hill Country Fare, Horizon, Kite Hill, Kraft, La
   Vaquita, Level Valley, Miceli's, Miyoko's Creamery, Moon Cheese,
   Nancy's, nickelodeon, Organic Pastures, Organic Valley, Philadelphia,
   Racconto, Roth, Sargento, Tillamook, Tofutti, Velveeta, Violife, and
   WW.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): cart

Your shopping cart contains:
Cart contains 0 items, for a total cost of $0.00

Enter a command (help, exit, brands, search, add, remove, cart, checkout): CHECKout

You have purchased the following items:
Summary: 0 items for a total cost of $0.00

Thanks for shopping with us! Please come back soon.

> python Project3.py
Enter data filename: Cheeses.csv
Creating product database from file: Cheeses.csv

Welcome to the online shopping app. We have a large selection of cheeses
available from many popular brands. Happy shopping!

Enter a command (help, exit, brands, search, add, remove, cart, checkout): exit

Thanks for shopping with us! Please come back soon.

> python Project3.py
Enter data filename: Cheeses.csv
Creating product database from file: Cheeses.csv

Welcome to the online shopping app. We have a large selection of cheeses
available from many popular brands. Happy shopping!

Enter a command (help, exit, brands, search, add, remove, cart, checkout): search

  Brand (or return for any brand): 
  Product keywords (or return for any): strawberry

Found the following matching products:
  30:  $5.70 Daiya Cream Cheese Spread Strawberry; 8.00 oz
  224:  $2.20 HEB Strawberry Cream Cheese Spread; 8 oz
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
  421:  $5.19 Violife Dairy Free Just Like Strawberry Cream Cheese; 7.05 oz

Enter a command (help, exit, brands, search, add, remove, cart, checkout): add

  Enter product Sku to add to cart: 313

Enter a command (help, exit, brands, search, add, remove, cart, checkout): add 

  Enter product Sku to add to cart: 421

Enter a command (help, exit, brands, search, add, remove, cart, checkout): add 

  Enter product Sku to add to cart: 313

Enter a command (help, exit, brands, search, add, remove, cart, checkout): cart

Your shopping cart contains:
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
  421:  $5.19 Violife Dairy Free Just Like Strawberry Cream Cheese; 7.05 oz
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
Cart contains 3 items, for a total cost of $13.47

Enter a command (help, exit, brands, search, add, remove, cart, checkout): search

  Brand (or return for any brand): heb
  Product keywords (or return for any): low fat string

No matching products located.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): gimme some cheese

Sorry, your command wasn't recognized. Try again.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): search

  Brand (or return for any brand): heb
  Product keywords (or return for any): low fat

Found the following matching products:
  199:  $3.11 HEB Reduced Fat Low Moisture Part-Skim Mozzarella Shredded Cheese; 8 oz

Enter a command (help, exit, brands, search, add, remove, cart, checkout): add

  Enter product Sku to add to cart: 199

Enter a command (help, exit, brands, search, add, remove, cart, checkout): 

Sorry, your command wasn't recognized. Try again.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): search

  Brand (or return for any brand): 
  Product keywords (or return for any): low fat string

Found the following matching products:
  380:  $5.14 SARGENTO Light Reduced Fat Low Moisture Mozzarella String Cheese; 12 ct

Enter a command (help, exit, brands, search, add, remove, cart, checkout): add

  Enter product Sku to add to cart: 380

Enter a command (help, exit, brands, search, add, remove, cart, checkout): cart

Your shopping cart contains:
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
  421:  $5.19 Violife Dairy Free Just Like Strawberry Cream Cheese; 7.05 oz
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
  199:  $3.11 HEB Reduced Fat Low Moisture Part-Skim Mozzarella Shredded Cheese; 8 oz
  380:  $5.14 SARGENTO Light Reduced Fat Low Moisture Mozzarella String Cheese; 12 ct
Cart contains 5 items, for a total cost of $21.72

Enter a command (help, exit, brands, search, add, remove, cart, checkout): remove

  Enter product Sku to remove from cart: 313

Enter a command (help, exit, brands, search, add, remove, cart, checkout): cart

Your shopping cart contains:
  421:  $5.19 Violife Dairy Free Just Like Strawberry Cream Cheese; 7.05 oz
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
  199:  $3.11 HEB Reduced Fat Low Moisture Part-Skim Mozzarella Shredded Cheese; 8 oz
  380:  $5.14 SARGENTO Light Reduced Fat Low Moisture Mozzarella String Cheese; 12 ct
Cart contains 4 items, for a total cost of $17.58

Enter a command (help, exit, brands, search, add, remove, cart, checkout): remove

  Enter product Sku to remove from cart: 380

Enter a command (help, exit, brands, search, add, remove, cart, checkout): search

  Brand (or return for any brand): 
  Product keywords (or return for any): blueberry

Found the following matching products:
  361:  $4.14 Philadelphia Blueberry Cream Cheese; 7.5 oz

Enter a command (help, exit, brands, search, add, remove, cart, checkout): add

  Enter product Sku to add to cart: 1000
No product with Sku 1000 found.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): cart

Your shopping cart contains:
  421:  $5.19 Violife Dairy Free Just Like Strawberry Cream Cheese; 7.05 oz
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
  199:  $3.11 HEB Reduced Fat Low Moisture Part-Skim Mozzarella Shredded Cheese; 8 oz
Cart contains 3 items, for a total cost of $12.44

Enter a command (help, exit, brands, search, add, remove, cart, checkout): remove

  Enter product Sku to remove from cart: 1000
No product with Sku 1000 found.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): remove 200

Sorry, your command wasn't recognized. Try again.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): remove

  Enter product Sku to remove from cart: 200
No product with Sku 200 found.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): cart

Your shopping cart contains:
  421:  $5.19 Violife Dairy Free Just Like Strawberry Cream Cheese; 7.05 oz
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
  199:  $3.11 HEB Reduced Fat Low Moisture Part-Skim Mozzarella Shredded Cheese; 8 oz
Cart contains 3 items, for a total cost of $12.44

Enter a command (help, exit, brands, search, add, remove, cart, checkout): remove

  Enter product Sku to remove from cart: 199

Enter a command (help, exit, brands, search, add, remove, cart, checkout): remove 

  Enter product Sku to remove from cart: 199
No product with Sku 199 found.

Enter a command (help, exit, brands, search, add, remove, cart, checkout): cart

Your shopping cart contains:
  421:  $5.19 Violife Dairy Free Just Like Strawberry Cream Cheese; 7.05 oz
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
Cart contains 2 items, for a total cost of $9.33

Enter a command (help, exit, brands, search, add, remove, cart, checkout): checkout

You have purchased the following items:
  421:  $5.19 Violife Dairy Free Just Like Strawberry Cream Cheese; 7.05 oz
  313:  $4.14 Kraft Philadelphia Strawberry Cream Cheese Spread; 7.5 oz
Summary: 2 items for a total cost of $9.33

Thanks for shopping with us! Please come back soon.

Turning in the Assignment:

The program should be in a file named Project3.py. Submit the file via Canvas before the deadline shown at the top of this page. Submit it to the assignment project3 under the assignments sections by uploading your python file.

Your file must compile and run before submission. It must also contain a header with the following format:

# File: Project3.py
# Student: 
# UT EID:
# Course Name: CS303E
# 
# Date Created:
# Description of Program: 

Programming Tips:

I'm sure you've used systems that required you to have every keystroke perfect or it wouldn't do anything. How annoying is that! I try always to make my code user friendly. There are lots of ways to do that. (You're not required to do any of these, except make things case insensitive.)

Allow alternatives: If exit works, why not quit or leave. If help works, why not a question mark? Your users will thank you. Notice you don't need to advertise such commands in the help message. But if the user is totally lost, it's always nice if they can type "?" and get some useful information.

Command completion: Often all of the available commands are uniquely determined by the initial letter, so really, you'd only need to consider the first letter. In general, any unique prefix should suffice. In practice, this is a bit hard to accomplish. Of course, Python has libraries to help you with this, though they are well beyond this course and may depend on your operating system.

Case shouldn't matter unless it should: I typically try to make case irrelevant in user commands. If the interface involves proper names, maybe you'd like to preserve those. But who really cares if you type "heb" instead of "HEB".

BTW: It's possible to be too user friendly. There used to be a version of the Lisp language that had a feature called DWIM ('Do what I mean'). If you typed an illegal command, DWIM would try to guess what you intended, and do that. This is the probably the worst idea in the history of programming languages! If your code is wrong, you want to know that and fix it. You don't want a program to second-guess what you intended. That's why I dislike auto-correct in text editors.