Day 13 marks the last lesson day before turning to an actual application build for the remainder of the challenge.
The Challenge:
-
Build a context manager class called
OrderSessionthat:- Takes a restaurant name on init
- On enter: prints
"Opening order session for {name}..."and returns itself - Has an
add_item(item, price)method that appends to an internalself.itemslist - Has a
get_total()method that returns the sum of all item prices - On exit: prints the session summary — number of items and total — then prints
"Session closed." - On exit: if an exception occurred, prints
"Session ended with error: {exc_val}"instead
-
Build the same thing as a
@contextmanagergenerator function calledorder_session(lowercase) — same behavior, different implementation style -
Test the class version with a normal order
-
Test the generator version with a normal order
-
Test the class version with an exception mid-session to prove error handling works — deliberately raise one inside the
withblock
My Code:
from contextlib import contextmanager
class OrderSession:
def __init__(self, restaurant_name):
self.restaurant_name = restaurant_name
self.items = []
def __enter__(self):
print(f"Opening order session for {self.restaurant_name}...")
return self
def add_item(self, item, price):
self.items.append((item, price))
def get_total(self):
return sum(price for _, price in self.items)
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is not None:
# An exception occurred during the session
print(f"Session ended with error: {exc_val}")
return False # Propagate the exception upward
print(f"--- Session Summary ---")
print(f"Items ordered: {len(self.items)}")
print(f"Total price: ${self.get_total():.2f}")
print("Session closed.")
return False
class OrderSessionGeneratorHelper:
def __init__(self):
self.items = []
def add_item(self, item, price):
self.items.append((item, price))
def get_total(self):
return sum(price for _, price in self.items)
@contextmanager
def order_session(restaurant_name):
print(f"Opening order session for {restaurant_name}...")
session = OrderSessionGeneratorHelper()
try:
yield session
print(f"--- Session Summary ---")
print(f"Items ordered: {len(session.items)}")
print(f"Total price: ${session.get_total():.2f}")
print("Session closed.")
except Exception as e:
print(f"Session ended with error: {e}")
raise
print("=== Test 1: Class-Based Version (Normal Order) ===")
with OrderSession("The Burger Joint") as session:
session.add_item("Classic Burger", 12.50)
session.add_item("Fries", 4.00)
session.add_item("Vanilla Shake", 6.00)
print(f"Running subtotal: ${session.get_total():.2f}")
print("\n=== Test 2: Generator-Based Version (Normal Order) ===")
with order_session("Pizza Palace") as session:
session.add_item("Large Pepperoni", 18.00)
session.add_item("Garlic Knots", 6.50)
print(f"Running subtotal: ${session.get_total():.2f}")
print("\n=== Test 3: Class-Based Version (With Exception Handling) ===")
try:
with OrderSession("Sushi World") as session:
session.add_item("Salmon Roll", 9.00)
session.add_item("Tuna Sashimi", 14.00)
print("... Uh oh, card machine broke mid-order! ...")
raise RuntimeError("Payment gateway timeout.")
session.add_item("Miso Soup", 3.00)
except RuntimeError:
print("Main program successfully caught the propagated exception.")
Running the Code:
=== Test 1: Class-Based Version (Normal Order) ===
Opening order session for The Burger Joint...
Running subtotal: $22.50
--- Session Summary ---
Items ordered: 3
Total price: $22.50
Session closed.
=== Test 2: Generator-Based Version (Normal Order) ===
Opening order session for Pizza Palace...
Running subtotal: $24.50
--- Session Summary ---
Items ordered: 2
Total price: $24.50
Session closed.
=== Test 3: Class-Based Version (With Exception Handling) ===
Opening order session for Sushi World...
... Uh oh, card machine broke mid-order! ...
Session ended with error: Payment gateway timeout.
Main program successfully caught the propagated exception.
It’s been fun doing these lessons when I have time and re-engaging the Python writing muscle, if you will.
Now we turn to the real point of learning to code, which is actually building something useful. So, I decided it would be neat to build a CLI (command line interface) tool that allows you to get a quick summary of the current headlines around AI and then have the option to open the full article.