This commit is contained in:
cutsweettea
2025-09-30 15:25:40 -04:00
commit 52ee1d7a8b
2 changed files with 203 additions and 0 deletions

107
book_stuff/book.py Normal file
View File

@@ -0,0 +1,107 @@
"""
This file is the beginnings of a Book class. However, it isn't very well-coded.
We want to harden it. We want to enforce the following rules:
- Title must not be blank, and cannot be longer than 255 characters.
- Authors is a list of names. None of the names should be blank or over 255 characters.
Names should not have any characters except for alphabetical ones.
- ISBN is a string, but it can only contain numbers and there must be 13 of them.
- Cost cannot be negative.
We are going to practice "test-driven development". This means we will write
the test cases for our code before we write our code. Enough of the code is
already given to you to show you how to use it. Don't update the code until
you have written tests to check for all of the above criteria. When your code passes
your tests, have your neighbor email you their tests and see if theirs passes as well.
If not, modify your code accordingly.
"""
class Book:
def __init__(self, title: str, authors: list[str], isbn: str, cost: float):
self.set_title(title)
self.set_authors(authors)
self.set_isbn(isbn)
self.set_cost(cost)
# --- Title ---
def get_title(self) -> str:
return self._title
def set_title(self, title: str) -> None:
# check if title is string
if not isinstance(title, str):
raise TypeError(f'title must be of type str, not {type(title).__name__}')
# check if title is blank or if the title length is greater than 255 characters
title_len = len(title)
if title_len < 1 or title_len > 255:
raise TypeError(f'title\'s length must be between 1 and 255, not {title_len}')
self._title = title
# --- Authors ---
def get_authors(self) -> list[str]:
return self._authors
def set_authors(self, authors: list[str]) -> None:
# check if authors is a list
if not isinstance(authors, list):
raise TypeError(f'authors must be of type list, not {type(authors).__name__}')
# check if authors is empty
authors_len = len(authors)
if authors_len == 0:
raise ValueError('authors list must not be empty')
for author in authors:
# check if each author is a string
if not isinstance(author, str):
raise TypeError(f'each author within authors must be of type str, not {type(author).__name__}')
# check if each author is alphanumeric
for author_name_part in author.split():
# splitting by space to check each part of the author's name, spaces aren't alpha so no author.isalpha()
if not author_name_part.isalpha():
raise ValueError(f'each part of the author\'s name within authors must be alphanumeric')
# check if each author's length is greater than 255
author_len = len(author)
if author_len > 255:
raise ValueError(f'each author\'s length within authors must be less than 256 characters')
self._authors = authors
# --- ISBN ---
def get_isbn(self) -> str:
return self._isbn
def set_isbn(self, isbn: str) -> None:
# check is isbn is 13 characters
isbn_len = len(isbn)
if isbn_len != 13:
raise ValueError(f'isbn\'s length must be 13 digits, not {isbn_len}')
# check if each character is a number
if not isbn.isdigit():
raise ValueError('each character in isbn must be a digit')
self._isbn = isbn
# --- Cost ---
def get_cost(self) -> float:
return self._cost
def set_cost(self, cost: float) -> None:
# check if cost is float
if not isinstance(cost, float):
raise ValueError(f'cost must be of type float, not {type(cost).__name__}')
# check if cost is negative
if cost < 0:
raise ValueError("cost cannot be negative")
self._cost = cost
# --- String representation ---
def __str__(self) -> str:
authors = ", ".join(self._authors)
return f"'{self._title}' by {authors} (ISBN: {self._isbn}, Cost: ${self._cost:.2f})"