The goal of this assignment is to work with object-oriented programming and exceptions in Python.
You will be doing your work in Python for this assignment. You may
choose to work on this assignment on a hosted environment (e.g. tiger) or on your own local
installation of Jupyter and Python. You should use Python 3.12 for your
work, but other recent versions should also work. To use tiger, use the
credentials you received. If you choose to work locally, Anaconda is the easiest way
to install and manage Python. If you choose to work locally, Anaconda, miniforge, or uv
are recommended methods to install and manage Python. If you work
locally, you may launch Jupyter Lab either from the Navigator
application or via the command-line as jupyter lab
.
In this assignment, we will be implementing a collection of classes that work together to orchestrate an online market. There will be products, including both grocery and household, the inventory, and a customer’s shopping cart. You will need to test your classes to make sure they work properly.
The assignment is due at 11:59pm on April 4.
You should submit the completed notebook file required for this
assignment on Blackboard. The
filename of the notebook should be a6.ipynb
.
Please make sure to follow instructions to receive full credit. Because you will be writing classes and adding to them, you do not need to separate each part of the assignment. Please document any shortcomings with your code. You may put the code for each part into one or more cells. Remember to redefine your class (execute the cell with the definition) before testing it.
The first cell of your notebook should be a markdown cell with a line for your name and a line for your Z-ID. If you wish to add other information (the assignment name, a description of the assignment), you may do so after these two lines.
Create four classes related to the products your online store will
sell: StoreItem, HouseholdItem, GroceryItem, BulkItem. StoreItem is the
base class which has a name, sku, and price. sku
is a
unique identifier for each item. GroceryItem subclasses from StoreItem
and has a nutrition field that defaults to an empty dictionary, and
HouseholdItem also is a subclass of StoreItem but has a brand name.
BulkItem subclasses from GroceryItem and adds a unit field (lbs, kg, ml,
oz). Add constructors and method(s) to support printing human-readable
strings for these items. Note that the bulk items should display there
units with the strings. Think about which class to put the method(s) in.
For example,
= GroceryItem("Cheerios", 38942, 3.99, {'calories': 200, 'fat': 0})
cereal = BulkItem("Bananas", 4011, 0.59, "lb")
bananas print(f"Two items: {cereal}, {bananas}")
prints
"Two items: Cheerios (38942) @ 3.99, Bananas (4011) @ 0.59/lb"
Create an Inventory class that stores both the items the store
carries and the amount of each item that the store has in stock. It
should have add_items
and remove_items
methods
that take a StoreItem object and an amount and adds or removes,
respectively, that to the current inventory. In addition, add a
find_item
method that takes a sku and returns the
StoreItem
object with that sku. It should also have a
method has_enough
that given an item and amount, returns a
boolean that indicates whether the inventory has more than that that
amount. Finally, add a method that again returns a human-readable string
with all the items in the inventory and their amounts.
Create a ShoppingCart class that tracks the items a customer wishes
to buy. It should store products and the amount of each item in the
cart. It should have add_items
and
remove_items
methods that take a StoreItem object and an
amount and adds or removes, respectively, that to the current cart.
Also, add a method that returns a human-readable string with all the
items in the cart and their amounts. In addition, add support for
+=
and -=
operators that will add or remove a
single (1) item (or unit) from the cart. Finally, add a cost method that
computes the total cost for all of the items in the cart.
Important: Think about the similarities between classes and
whether you can use OOP concepts to minimize your work for this
class.
The Store class will keep track of both the inventory and the
customers shopping. To that end, it has a get_cart
method
that returns a new ShoppingCart object and keeps track of it. Define a
max_carts
class variable that defaults to ten (10) as the
maximum number of carts in the store, and a class method
set_max_carts
that sets this variable, raising an exception
if this value is not a non-negative integer. get_cart
should then raise an exception if the store has too many carts are in
use. In addition, write a checkout
method that checks the
inventory to make sure the number of items being bought in the shopping
cart are available and then deducts the quantities selected in the
shopping cart from the inventory. If there is not enough left in the
inventory, the checkout method should raise an exception
alerting that about which item(s) are not in stock.
checkout
should return the cost of all the items bought and
remove the cart from the store.
We should add more exceptions to our classes to avoid particular issues. Here is the list of exceptions to raise and the circumstances:
BulkItem
.
Bulk items do allow fractional amounts!find_item
if the sku doesn’t
existremove_items
if more items are
removed from the inventory than exist.The final list of classes and methods to be added. Note that all classes should have constructors that properly initialize objects, and the instance fields are not listed here.
The following code should help you test your work:
= Store()
store "Cheerios", 38942, 3.99, {'calories': 200, 'fat': 0}), 10)
store.inventory.add_items(GroceryItem("Trash Bags", 38902, 5.99, "Hefty"), 30)
store.inventory.add_items(HouseholdItem("Bananas", 4011, 0.59, "lb"), 20)
store.inventory.add_items(BulkItem("Lettuce", 3982, 2.99, "head"), 25)
store.inventory.add_items(BulkItem("Oreos", 27894, 3.29), 1)
store.inventory.add_items(GroceryItem(
print("Inventory:")
print(store.inventory)
= store.get_cart()
my_cart 4011), 3)
my_cart.add_items(store.inventory.find_item(38902))
my_cart.add_items(store.inventory.find_item(27894), 1)
my_cart.add_items(store.inventory.find_item(print("Cart:")
print(my_cart)
= store.checkout(my_cart)
total_cost print(f"You spent ${total_cost}")
print("Updated Inventory:")
print(store.inventory)
which outputs something similar to:
Inventory:
10 Cheerios (38942) @ 3.99
30 Trash Bags (38902) @ 5.99
20 Bananas (4011) @ 0.59/lb
25 Lettuce (3982) @ 2.99/head
1 Oreos (27894) @ 3.29
Cart:
3 Bananas (4011) @ 0.59/lb
1 Trash Bags (38902) @ 5.99
1 Oreos (27894) @ 3.29
You spent $11.05
Updated Inventory:
10 Cheerios (38942) @ 3.99
29 Trash Bags (38902) @ 5.99
17 Bananas (4011) @ 0.59/lb
25 Lettuce (3982) @ 2.99/head
0 Oreos (27894) @ 3.29
This code should raise an exception (too many carts):
for i in range(20):
store.get_cart()
This code is ok.
30)
Store.set_max_carts(for i in range(20):
store.get_cart()
For CSCI 503 students, the following can be used to test Part 5:
= store.get_cart()
my_cart 4013), 3) # raises your exception
my_cart.add_items(store.inventory.find_item(38902), 1.5) # raises your exception
my_cart.add_items(store.inventory.find_item(27894), 3) # raises your exception store.inventory.remove_items(store.inventory.find_item(