question 178 Exceptions & Validation · medium
Redeem a coupon, or say exactly why not
The checkout shows a different message for each reason a coupon fails, so redeem must say which reason it was by raising a different error type. Define three error types and write redeem.
Error types
UnknownCoupon, CouponExpired and CouponUsedUp, each a kind of ExceptionFunction
redeem(coupons, code, today); coupons maps a code to {"uses_left": int, "expires": "YYYY-MM-DD"}; today is a "YYYY-MM-DD" textChecks, in orderunknown code →
UnknownCoupon; today after expires → CouponExpired (the expiry day itself is still valid); no uses left → CouponUsedUpOn successsubtract one use in place and return the uses left
Examples
callredeem({'SPRING10': {'uses_left': 2, 'expires': '2025-05-31'}, 'WELCOME': {'uses_left': 1, 'expires': '2026-12-31'}, 'VIP': {'uses_left': 0, 'expires': '2026-12-31'}}, 'WELCOME', '2025-06-01')returns0
callredeem({'SPRING10': {'uses_left': 2, 'expires': '2025-05-31'}, 'WELCOME': {'uses_left': 1, 'expires': '2026-12-31'}, 'VIP': {'uses_left': 0, 'expires': '2026-12-31'}}, 'SPRING10', '2025-04-02')returns1
callredeem({'SPRING10': {'uses_left': 2, 'expires': '2025-05-31'}, 'WELCOME': {'uses_left': 1, 'expires': '2026-12-31'}, 'VIP': {'uses_left': 0, 'expires': '2026-12-31'}}, 'FREESHIP', '2025-04-02')raisesUnknownCoupon
callredeem({'SPRING10': {'uses_left': 2, 'expires': '2025-05-31'}, 'WELCOME': {'uses_left': 1, 'expires': '2026-12-31'}, 'VIP': {'uses_left': 0, 'expires': '2026-12-31'}}, 'SPRING10', '2025-06-01')raisesCouponExpired
callredeem({'SPRING10': {'uses_left': 2, 'expires': '2025-05-31'}, 'WELCOME': {'uses_left': 1, 'expires': '2026-12-31'}, 'VIP': {'uses_left': 0, 'expires': '2026-12-31'}}, 'VIP', '2025-06-01')raisesCouponUsedUp
callredeem({'SPRING10': {'uses_left': 2, 'expires': '2025-05-31'}, 'WELCOME': {'uses_left': 1, 'expires': '2026-12-31'}, 'VIP': {'uses_left': 0, 'expires': '2026-12-31'}}, 'SPRING10', '2025-04-02')returns1