"""library.py, version 2: adds due dates, overdue lists and DVDs.
Existing code that uses Book and Library from version 1 still works.
"""
from datetime import date, timedelta
class LibraryItem:
"""Anything the library lends. Subclasses set LOAN_DAYS."""
LOAN_DAYS = 21
def __init__(self, title):
self.title = title
self.borrower = None
self.due = None
def is_available(self):
return self.borrower is None
class Book(LibraryItem):
def __init__(self, title, author): # same signature as version 1
super().__init__(title)
self.author = author
def __str__(self):
return f"{self.title} by {self.author}"
class DVD(LibraryItem):
LOAN_DAYS = 7 # overrides the class attribute
def __str__(self):
return f"{self.title} (DVD)"
class Library:
def __init__(self):
self._items = []
def add(self, item):
self._items.append(item)
def find(self, title):
"""Return the item with this title (any capitals), or None."""
for item in self._items:
if item.title.lower() == title.lower():
return item
return None
def check_out(self, title, borrower, today=None):
"""Lend an item. Return True on success, False if missing or out.
today defaults to the real date; tests can pass a fixed date.
"""
item = self.find(title)
if item is None or not item.is_available():
return False
if today is None:
today = date.today()
item.borrower = borrower
item.due = today + timedelta(days=item.LOAN_DAYS)
return True
def overdue(self, today):
"""Return the items that are out and past their due date."""
late = []
for item in self._items:
if item.borrower is not None and item.due < today:
late.append(item)
return late