The OOP System
Advanced · 90 min build · 🏆 milestone project
One object is easy. A system is where your design gets tested. Your goal is to build a library manager, a text-based program that tracks books, members, checkouts, due dates, and returns using classes that cooperate instead of one giant script.
You are practicing the Part III skill: think in objects. The finished system should use classes, inheritance, dunder methods, and at least one decorator, while also using regex for catalog IDs and datetime for due dates.
What you'll build
You will build one menu-driven library manager with these routes:
1: list the catalog.2: check out an item to a member.3: return an item.4: show a short library summary.7: exit cleanly.
A catalog item is one thing the library can lend, such as a book or audiobook. A loan is the act of assigning an item to a member until a due date. The scaffold is starter code with TODO comments that show where your work belongs. The acceptance criteria are checks you can run yourself to prove each stage works.
The design picture is the house-blueprint idea from OOP: LibraryItem is the base blueprint, and Book and AudioBook are revised blueprints based on it. Library is the front desk that stores items and sends work to the right object.
Checkpoint 1: the object model
Start by making the object blueprints honest. Keep data that belongs to one item inside LibraryItem, and keep catalog-wide behavior inside Library.
Acceptance criteria:
- Creating
Book("LIB-001", "Python Field Notes", "Ada Stone", 240)works. - Creating an item with
"BAD-1"raisesValueError: catalog IDs must look like LIB-001. item.is_availablereturnsTruebefore checkout.str(item)shows the catalog ID, title, and status.repr(item)gives a developer-facing representation that includes the class name.
Checkpoint 2: inheritance and dunder methods
Now make the subclasses earn their place. Book and AudioBook should share lending behavior from LibraryItem, then add their own details.
Acceptance criteria:
BookandAudioBookboth inheritcheckout()andreturn_item()fromLibraryItem.len(book)returns the page count.len(audio_book)returns the minute count.len(library)returns the number of catalog items."LIB-001" in libraryreturnsTruewhen that item exists andFalsewhen it does not.
Checkpoint 3: checkout, return, and due dates
Build the lending behavior next. This is where objects start cooperating: the menu talks to Library, Library finds one item, and the item updates its own state.
Acceptance criteria:
- Route
2asks for catalog ID and member name. - Checking out an available item stores the member name.
- The due date is
TODAY + timedelta(days=LOAN_DAYS). - Trying to check out an unavailable item prints who already has it.
- Route
3clearschecked_out_byanddue_at. - The
@log_actiondecorator runs after checkout and return.
Checkpoint 4: validation and search
Use the text and time tools from Section 13 where they belong. Regex should check catalog ID shape, and datetime should represent due dates.
Acceptance criteria:
find_by_id()returns the matching item object, not a string or dictionary.- Unknown catalog IDs print
No item found for LIB-999.or the matching ID. - Catalog IDs are normalized with
.strip().upper()before lookup. - Due dates are aware datetimes using
ZoneInfo("Asia/Kolkata"). - Listing the catalog after a checkout shows the changed status.
Checkpoint 5: test the full system
Walk every route like a user. A project is not done because one happy path worked.
Acceptance criteria:
- Entering
7printsGoodbyeand exits. - Route
1lists all demo items. - Route
4shows item, available, and checked-out counts. - Checkout followed by catalog listing shows the item as unavailable.
- Return followed by summary increases the available count.
- The code has no giant route that edits every detail directly; objects own their own behavior.
Stretch goals
Choose one or two after the base system works:
- Add a
Memberclass with__str__and a list of checked-out catalog IDs. - Add a
DigitalBooksubclass with a download size. - Add a route that lists overdue items by comparing
due_atto a fixed aware datetime. - Save and load the catalog in JSON during one page session.
- Add a custom class decorator that registers every item type by name.
How to get unstuck
If the class shape gets fuzzy, revisit Thinking in Objects and Classes & Instances. If subclass behavior feels duplicated, go back to Inheritance. If len(item), str(item), or "LIB-001" in library surprises you, rebuild the examples from Special Dunder Methods. If the decorator wrapper gets noisy, compare it to Decorators. If ID validation or due dates fail, return to Regular Expressions and Dates, Times & Time Zones.
Part III is complete when this project feels like a set of cooperating objects, not one long script. Part IV shifts the focus from building programs that work to shaping programs that stay readable, testable, and professional as they grow.