The goal of this assignment is to work with object-oriented programming and exceptions in Python.
You will be doing your work in a Jupyter notebook for this
assignment. You may choose to work on this assignment on a hosted
environment (e.g. tiger)
or on your own local installation of Jupyter and Python. You should use
Python 3.13 for your work. (Older versions may work, but your code will
be checked with Python 3.13.) To use tiger, use the credentials you
received. If you work remotely, make sure to download the .ipynb file to
turn in. If you choose to work locally, Anaconda, miniforge, or uv are probably the easiest ways
to install and manage Python. You can start JupyterLab either from the
Navigator application (anaconda) or via the command-line as
jupyter-lab or jupyter lab.
In this assignment, we will be implementing a collection of classes that work together to orchestrate a library. There will be media items, including books, movies, and albums, library copes of those items, library patrons, and the library itself. You will need to test your classes to make sure they work properly.
The assignment is due at 11:59pm on November 7.
You should submit the completed notebook file required for this
assignment on Blackboard. The
filename of the notebook should be a6.ipynb.
Please make sure to follow instructions to receive full credit. Because you will be writing classes and adding to them, you do not need to separate each part of the assignment. Please document any shortcomings with your code. You may put the code for each part into one or more cells. Remember to redefine your class (execute the cell with the definition) before testing it.
The first cell of your notebook should be a markdown cell with a line for your name and a line for your Z-ID. If you wish to add other information (the assignment name, a description of the assignment), you may do so after these two lines.
Create four classes related to the items your library will have:
MediaItem, Book, Movie, and
Album. A Book should have an id, title, year of release,
author, and number of pages. A Movie should have an id, title, year of
release, director, and duration in minutes. An Album should have an id,
title, year of release, artist, and number of tracks. MediaItem should
be the base class for these items. Add constructors and method(s) to
support printing human-readable strings for these items.
Important: You need to define these classes using
inheritance for full credit with MediaItem as the base
class. You should be able to create these items as follows:
book = Book(id=1927931, title="To Kill a Mockingbird", year=1960, author="Harper Lee", pages=281)
movie = Movie(id=2890123, title="Inception", year=2010, director="Christopher Nolan", duration=148)
album = Album(id=3948123, title="Abbey Road", year=1969, artist="The Beatles", tracks=17)
print('Item:', book) # prints "Item: To Kill a Mockingbird (1927931), Harper Lee, 1960, 281 pages"
print('Item:', movie) # prints "Item: Inception (2890123), Christopher Nolan, 2010, 148 minutes"
print('Item:', album) # prints "Item: Abbey Road (3948123), The Beatles, 1969, 17 tracks"Create a LibraryCopy class to keep track of a copy of a
MediaItem and whether it is checked out or not. The library may keep
multiple copies of an item. It should have a constructor that takes a
MediaItem object, copy number (copy_num), and
return_date. The return_date should be
initialized to None indicating it is available. Create a
checkout method that takes the return date as an argument,
and a checkin method that takes no argument but sets the
return date to None. Also, create an available
property that returns an item’s availability as a
boolean. If an item is already checked out and checkout is
called, raise an exception. Finally, add a method that returns a
human-readable string with the media item’s information as well as
whether it is checked out or not. For example:
mock1 = LibraryCopy(book, copy_num=1)
mock2 = LibraryCopy(book, copy_num=2)
mock2.checkout('2025-11-15')
mock2.checkout('2025-11-16') # raise exception that already checked out
print(mock2.available) # print False
print(mock1.available) # print True
print(mock1) # prints "To Kill a Mockingbird (1927931), Harper Lee, 1960, 281 pages [Copy 1, Available]"
print(mock2) # prints "To Kill a Mockingbird (1927931), Harper Lee, 1960, 281 pages [Copy 2, Checked Out, Due 2025-11-15]"Create AdultPatron and ChildPatron classes
that represents patrons of the library. A patron has a name, id number,
and a collection of items currently checked out. An adult patron may
have no more than ten (10) items checked out at a time; a child patron
may have no more than five (5) items checked out at a time. Add methods
checkout and checkin that take a LibraryCopy
object and adds or removes, respectively, that item to the patron’s
collection of checked out items. If a patron tries to check out more
than the allowed number of items, raise an exception. Finally, add a
method that returns a human-readable string with the patron’s name, id
number, and all the items currently checked out.
Important: You need to design these classes using
inheritance to receive full credit.
Create a Library class that keeps track of both the library copies as
well as the patrons. It’s constructor should take a name, a list of
items, and a list of patrons. It has an add_copy method
that takes a LibraryCopy object and adds it to the library’s collection.
It also has an add_patron method that takes a Patron object
and adds it to the library’s list of patrons. Define a
checkout method that takes a patron id number, a media item
id, and a return date, and checks out a library copy of item to the
patron, raising exceptions if the patron does not exist, the item does
not exist, there are no copies available, the patron already checked out
that media item, or the patron cannot check out any more items.
Similarly, define a checkin method that takes a patron id
number and a media item id and returns the item from the patron, raising
exceptions if the patron does not exist, the item does not exist, or the
patron does not have that item checked out. Finally, add a method that
returns a human-readable string with all the items in the library and
all the patrons.
collections
package may be useful here.Add support for the += and -= operators to
the Library classes to add and remove items or patrons from the library.
For example, the following code should work:
library = Library(name="Sycamore Library")
library += mock1
library += mock2
library += patron
library -= mock1Note that we have not implemented removing patrons or copies in Part 4 so you will need to add this functionality!
The final list of classes and methods to be added. Note that all classes should have constructors that properly initialize objects, and the instance fields are not listed here.
checkout methodcheckin methodavailable propertycheckout methodcheckin methodcheckout methodcheckin methodremove_copy methodremove_patron method+= operator-= operatorThe following code should help you test your work (Updated 2025-10-29):
book = Book(id=1927931, title="To Kill a Mockingbird", year=1960, author="Harper Lee", pages=281)
movie = Movie(id=2890123, title="Inception", year=2010, director="Christopher Nolan", duration=148)
movie2 = Movie(id=6739021, title="Lady Bird", year=2017, director="Greta Gerwig", duration=94)
album = Album(id=3948123, title="Abbey Road", year=1969, artist="The Beatles", tracks=17)
mock1 = LibraryCopy(book, copy_num=1)
mock2 = LibraryCopy(book, copy_num=2)
incep = LibraryCopy(movie, copy_num=1)
lb1 = LibraryCopy(movie2, copy_num=1)
lb2 = LibraryCopy(movie2, copy_num=2)
beatles = LibraryCopy(album, copy_num=1)
ananya = AdultPatron("Ananya Reddy", id=347)
rafael = ChildPatron("Rafael Lopez", id=651)
library = Library(name="Sycamore Library", items=[mock1, mock2, incep, lb1, lb2, beatles], patrons=[ananya, rafael])
library.checkout(347, 6739021, '2025-11-08')
library.checkout(347, 3948123, '2025-11-15')
library.checkout(651, 6739021, '2025-11-09')
library.checkout(651, 3948123, '2025-11-16') # raises exception
library.checkin(347, 3948123)
library.checkout(651, 3948123, '2025-11-17')
print(library)
print(ananya)
print(rafael)which outputs something similar to:
Sycamore Library
Patrons:
Patron: Ananya Reddy (347), Checked out items:
Lady Bird (6739021), Greta Gerwig, 2017, 94 min [Copy 1, Checked Out, Due 2025-11-08]
Patron: Rafael Lopez (651), Checked out items:
Lady Bird (6739021), Greta Gerwig, 2017, 94 min [Copy 2, Checked Out, Due 2025-11-09]
Abbey Road (3948123), The Beatles, 1969, 17 tracks [Copy 1, Checked Out, Due 2025-11-17]
Items:
To Kill a Mockingbird (1927931), Harper Lee, 1960, 281 pages [Copy 1, Available]
To Kill a Mockingbird (1927931), Harper Lee, 1960, 281 pages [Copy 2, Available]
Inception (2890123), Christopher Nolan, 2010, 148 min [Copy 1, Available]
Lady Bird (6739021), Greta Gerwig, 2017, 94 min [Copy 1, Checked Out, Due 2025-11-08]
Lady Bird (6739021), Greta Gerwig, 2017, 94 min [Copy 2, Checked Out, Due 2025-11-09]
Abbey Road (3948123), The Beatles, 1969, 17 tracks [Copy 1, Checked Out, Due 2025-11-17]
Ananya Reddy (347), Checked out items:
Lady Bird (6739021), Greta Gerwig, 2017, 94 min [Copy 1, Checked Out, Due 2025-11-08]
Rafael Lopez (651), Checked out items:
Lady Bird (6739021), Greta Gerwig, 2017, 94 min [Copy 2, Checked Out, Due 2025-11-09]
Abbey Road (3948123), The Beatles, 1969, 17 tracks [Copy 1, Checked Out, Due 2025-11-17]
You should also consider testing the exceptions. For example,
for test_album_num in range(10):
test_album = Album(id=test_album_num, title=f"Test Album {i}", year=2025, artist="Me", tracks=67)
test_copy = LibraryCopy(test_album, copy_num=1)
library.add_item(test_copy)
for test_album_num in range(10):
print("Checking out", test_album_num)
library.checkout(347, test_album_num, "2025-11-20")
# raises exception on test_ablum 9
for test_album_num in range(10):
print("Checking in", test_album_num)
library.checkin(347, test_album_num)
for test_album_num in range(10):
print("Checking out", test_album_num)
library.checkout(651, test_album_num, "2025-11-21")
# raises exception on test_album 3
datetime library and its now method and
incorporate this into the human readable string (15 pts)