Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 52 additions & 21 deletions samples/book-app-project/book_app.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import sys
from books import BookCollection
from books import Book, BookCollection


# Global collection instance
collection = BookCollection()


def show_books(books):
def show_books(books: list[Book]) -> None:
"""Display books in a user-friendly format."""
if not books:
print("No books found.")
Expand All @@ -21,27 +21,34 @@ def show_books(books):
print()


def handle_list():
def handle_list() -> None:
books = collection.list_books()
show_books(books)


def handle_add():
def handle_add() -> None:
print("\nAdd a New Book\n")

title = input("Title: ").strip()
author = input("Author: ").strip()
year_str = input("Year: ").strip()

if not year_str:
print("\nError: Year cannot be empty.\n")
return

try:
year = int(year_str) if year_str else 0
year = int(year_str)
if year < 1 or year > 2100:
print("\nError: Year must be between 1 and 2100.\n")
return
collection.add_book(title, author, year)
Comment on lines +36 to 45
print("\nBook added successfully.\n")
except ValueError as e:
print(f"\nError: {e}\n")


def handle_remove():
def handle_remove() -> None:
print("\nRemove a Book\n")

title = input("Enter the title of the book to remove: ").strip()
Expand All @@ -50,7 +57,7 @@ def handle_remove():
print("\nBook removed if it existed.\n")


def handle_find():
def handle_find() -> None:
print("\nFind Books by Author\n")

author = input("Author name: ").strip()
Expand All @@ -59,39 +66,63 @@ def handle_find():
show_books(books)


def show_help():
def handle_search() -> None:
print("\nSearch Books\n")

query = input("Search query (title or author): ").strip()
if not query:
print("\nError: Search query cannot be empty.\n")
return

books = collection.search_books(query)
show_books(books)


def handle_list_unread() -> None:
books = collection.get_unread_books()
show_books(books)


def show_help() -> None:
print("""
Book Collection Helper

Commands:
list - Show all books
unread - Show only unread books
add - Add a new book
remove - Remove a book by title
find - Find books by author
find - Find books by author (exact match)
search - Search books by title or author (partial match)
help - Show this help message
""")


def main():
COMMANDS = {
"list": handle_list,
"unread": handle_list_unread,
"add": handle_add,
"remove": handle_remove,
"find": handle_find,
"search": handle_search,
"help": show_help,
}
Comment on lines +101 to +109


def main() -> None:
if len(sys.argv) < 2:
show_help()
return

command = sys.argv[1].lower()
handler = COMMANDS.get(command)

if command == "list":
handle_list()
elif command == "add":
handle_add()
elif command == "remove":
handle_remove()
elif command == "find":
handle_find()
elif command == "help":
show_help()
if handler:
handler()
else:
print("Unknown command.\n")
print(f"Unknown command: '{command}'\n")
show_help()
sys.exit(1)


if __name__ == "__main__":
Expand Down
11 changes: 11 additions & 0 deletions samples/book-app-project/books.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def save_books(self):
json.dump([asdict(b) for b in self.books], f, indent=2)

def add_book(self, title: str, author: str, year: int) -> Book:
if year < 1 or year > 2100:
raise ValueError(f"Year must be between 1 and 2100, got {year}.")
book = Book(title=title, author=author, year=year)
self.books.append(book)
self.save_books()
Expand Down Expand Up @@ -70,3 +72,12 @@ def remove_book(self, title: str) -> bool:
def find_by_author(self, author: str) -> List[Book]:
"""Find all books by a given author."""
return [b for b in self.books if b.author.lower() == author.lower()]

def search_books(self, query: str) -> List[Book]:
"""Find books where query matches (partial, case-insensitive) title or author."""
q = query.lower()
return [b for b in self.books if q in b.title.lower() or q in b.author.lower()]

def get_unread_books(self) -> List[Book]:
"""Return all books that have not been marked as read."""
return [b for b in self.books if not b.read]
Loading
Loading