02 Intermediate Python: OOP, Types, Errors & Testing/2.14 Lab code (reference solutions)/2.14.2 lab/library/library.py
§ 2.14.2section 16 of 20·~6 min
lab/library/library.py
from library.models import Book, Member
MAX_BOOKS_PER_MEMBER = 3
class BookNotAvailableError(Exception):
"""Raised when a book is already issued to someone."""
class Library:
def __init__(self) -> None:
self.books: dict[str, Book] = {}
self.members: dict[str, Member] = {}
def add_book(self, book: Book) -> None:
if book.isbn in self.books:
raise ValueError(f"Duplicate ISBN {book.isbn}")
self.books[book.isbn] = book
def add_member(self, member: Member) -> None:
self.members[member.member_id] = member
def issue_book(self, isbn: str, member_id: str) -> None:
book = self.books[isbn]
member = self.members[member_id]
if not book.available:
raise BookNotAvailableError(f"'{book.title}' is issued to {book.issued_to}")
if len(member.borrowed) >= MAX_BOOKS_PER_MEMBER:
raise ValueError(f"{member.name} already has {MAX_BOOKS_PER_MEMBER} books")
book.issued_to = member_id
member.borrowed.append(isbn)
def return_book(self, isbn: str) -> None:
book = self.books[isbn]
if book.available:
raise ValueError(f"'{book.title}' is not issued")
self.members[book.issued_to].borrowed.remove(isbn)
book.issued_to = None
def search(self, query: str) -> list[Book]:
q = query.lower()
return [b for b in self.books.values() if q in b.title.lower() or q in b.author.lower()]