Homework 9: Book Bandit (Part One)
Due: Tuesday April 28th, 2020 at 9:00PM anywhere in the world.
For a summary of all handout corrections/frequently asked questions about this homework, please continue referring to this Campuswire post!


Setup and Handin
For this homework, we are providing you with some source code, including a stencil for hw9_code.py
, in which you will write all of your code. We’ll also be providing you with a file that will contain all of your tests called hw9_test.py
.A zip file containing the source code, including the stencil and testing file, can be downloaded here.
When finished, hand in your hw9_code.py
and hw9_test.py
into Gradescope. Make sure to use your anonymous account!
The Assignment
Yee-haw! The tyrannical sheriff has gone rogue and started outlawing books left and right. You are a book-loving, entrepreneurial cowboy and you’ve accumulated a wide range of contraband books that you want to sell because it’s important literature.
There’s one problem though…
The cowboy book club doesn’t know which books they want to buy (they’re indecisive) and so it’s up to you to help them out (so you can reap the profits).
You must build a system so that:
(1) customers can browse, check out and buy those books (without the sheriff knowing),
(2) they can get recommendations for what books to buy,
(3) display this all on a website!
The website has already been handled for you, with details about how to run it described below. In this homework assignment, we’ll also be doing the recomendations part for you this time around, but don’t worry, you’ll get your turn at the rodeo! This is the first part of a two-part homework assignment that will lead to you completing what would have previously been the third project.
Resources We Provide
- Flask: This will power the local “website” you interact with (we’ve handled this for you)
- Book & genre data
Click for more details about the website!
Home page
The home page shows a collection of books, organized by genre. There is no particular order to these books, they should be chosen randomly from the dataset every time the page is loaded.
Recommendations page
The recommendations page shows a list of books, sorted by how highly the system ranks those books for the user (for example, a book with 7 points comes before a book with 3 points; the point system is detailed below in the implementation details section).
Search page
The search page shows a list of books matching the user’s search query, sorted by the rating of the books in descending order (for example, 4.8 stars comes before 3.5 stars).
Viewing page
The book viewing page gives you more information about a book, and allows you to add the book to your cart.
Cart page
The cart displays all the books in the user’s cart, allowing them to remove individual books and purchase all the books in the cart.
Each page has a header with links to useful pages and a search bar to look for books, and a footer that displays the book covers of the user’s previously purchased books.
Tasks
For this homework, you’ll be handling four major components of the backbone of our website:
- Internally representing our data, stored in a CSV, as a list of Books
- Keeping track of a cart of books, which we can add and remove things from
- Keeping track of a set of purchased books, for when we buy books from our cart
- Searching for a book based on title, author, or genre
Functions to Implement
In the stencil, we’ve instantiated four global lists. For this homework, you’ll be working with three of them: book_master_list
, cart
, and purchases
. You’ll be working on the following functions. Please read the information below carefully.
Note: Functions with no output types don’t return anything.
-
setup():
Reads through the CSV file and creates a master list of books, b by ID (which you assign). The ID assigned to each Book should just be its index in the master list. For help figuring out how to read a CSV file, look at the example below. You can also find more examples in the solution to Lab 10.
CSV Processing Example
@dataclass
class Posn:
x : int
y : int
with open('books.csv') as f:
lines = list(csv.reader(f))
for line in lines:
my_posn = Posn(line[0], line[1])
-
get_cart() -> list:
Returns the current shopping cart of books.
-
get_book(ident: int) -> Book
Returns the book with ID ident
(e.g. 1). If a book with the IDident
is not found, you can raise an error using raise ValueError(<string>)
. For example:
def divide(num1, num2):
if num2 != 0:
return num1 / num2
else:
raise ValueError("Cannot divide by zero")
This might be helpful with debugging, and is also good coding practice. For more information about how to test errors, take a look at the Python testing guide.
-
add_book_to_cart(ident: int):
Adds the book identified by the index ident
to the cart. You cannot have duplicates of books in a cart.
-
remove_book_from_cart(ident: int):
Removes a book from the cart at index ident
(e.g. 1) if it is in the cart.
-
buy_books_in_cart():
Buys all books in the cart. You should call update_recs
(a function we’ve provided; see Implementations We Provide below) on each book in your cart before moving it to the purchases. At the end, your cart should be empty! Also, books can be bought twice.
-
search_books(query: str) -> list:
Given a query, return up to 20 of the books that contain the query in the title, author, or genre (case-insensitive in both directions). If there are fewer than 20 books that match, return all of those books.
-
make_genre_list(list) -> list:
Creates a list of lists (we’re calling itgenre_list
), with each sublist representing one genre. For this homework assignment, we only have 5 genres. These lists must come in the order we specify. Check out the Implementations We Provide section for more information about genre_list
.
-
get_purchases() -> list:
Returns all purchased books.
-
book_matches(query: str, book: Book)->bool
Checks to see if given the query if its in the book’s title, author, or genre.
Note: Throughout the stencil, you might see the keyword global
sprinkled throughout the functions (i.e., global book_master_list
). This tells Python that, even within the individual functions, they should be referencing the same list that was defined globally at the top.
Note: You might notice that several of the methods above merely return one of the data structures we’re keeping track of globally! These get-functions might seem kind of useless at first, but these are important in making sure that external Python files (such as app.py
, which will be used to run our website) can access the data contained in hw9_code.py
.
If you take classes such as CS112 or CS18, you’ll learn more about the importance of get-functions!
Implementations We Provide
In the stencil code, there might be things that might seem unfamiliar. Please read the information below to get a better understanding of what’s going on.
-
Dataclasses: We’ve provided you with the Book and BookScorePair dataclasses. Please don’t modify these dataclasses.
-
Recommendations: In the code, we give you the implementations for get_recommendations
, update_recs
, and update_recs_given_query_words
. These functions keep track of a recommendations score for each Book based on the user’s actions. These scores are kept track of using the BookScorePair
dataclass, which is described below. Please don’t modify these functions.
-
BookScorePair:
@dataclass
class BookScorePair:
book : Book
score : int
This dataclass represents a book and its respective recommendation score. How the user interacts with the website will change the score of the book. If you look at update_recommendations
, you can see it in use. Since you are not implementing the recommendation scoring system in this homework, you don’t have to worry about this dataclass other than making not to delete it.
-
Global variables/macros: In computer programs, it is common practice to use numbers to represent concepts to make code more readable. At the top of the stencil code, you’ll see some global variables, written in all caps, being set to numbers (ex: ART = 0
).
This allows us to use these words as numbers. This means we could do something like ART + 5
to get 5, but we can also do something more useful: using these globals to index into lists. (In other words, if we had some list called genre_list
, genre_list[ART]
would return the 0th (first) element of genre_list
.) The globals we have provided specify what order the inner lists of your genre_list
should be in. If you do not follow this, books will be mismatched to their genres in the website!
Running the code
The zip file we provide you contains all the files required for this assignment. Your code will go into hw9_code.py
.
To run the web app, you need to run app.py
(also in that folder). app.py
contains the code to create what is called a “Flask application.” Flask is a Python package (similar to how datetime and dataclasses are Python packages) which allows you to make web servers.
In PyCharm, run app.py
. You should see something like this:

While this is running, you will be able to go onto your web browser and go to the url that it gives you (http://127.0.0.1:5000
above) and see the web app! This will only work on the computer that is running the application.
You can only have one version of the web app running; if you try to run app.py
twice, you will see an error message. You should be able to have app.py
running constantly; if you then make changes to hw9_code.py
, the app will automatically reload itself and you can refresh the website.
If you are having a hard time running the web app, let the TAs know!
Testing Tips and Requirements
- Unlike HW7 and HW8, you’ll be writing your tests in a separate file, instead of directly in
hw9_code.py
.
- You do not have to test the get-functions (except for
get_book
, which you should test!) setup
, or anything we implement for you.
- If you create any helpers, make sure to thoroughly test them.
- To test
make_genre_list
, it might be helpful to construct your own smaller data to test this function exhaustively. Try to think of several edge cases.
- For functions that require accessing the global
book_master_list
, remember that the book_master_list
will be empty unless we call setup
or add to it ourselves. So, before we can test anytihng, we need to access it through the global
keyword, and then do something like this:
def test_search():
global book_master_list #this tells us to use the global variable, book_master_list
setup()
# now book_master_list is populated
test("Test for search", search_books("query"), ... )
Alternatively, we can also make our own smaller testing data:
def test_function_small():
global book_master_list
# we can manually add books to this list
book_master_list.append(Book("Hamlet", "Shakespeare", "Tragedy", "thisisanimage.jpg", 5.0, 5, 72))
test("Test for search", search_books("shake"), ...)
We’ve provided an example of how you might do this in hw9_test.py.
Grading Requirements
Minimum Functionality:
- Book information is read in from the dataset into a list for storing books.
- The website shows a home page with a selection of books from the overall dataset, categorized by genre.
- The user can add books to and remove books from their shopping cart.
Full Functionality:
- All of the above.
- Can keep track of purchased books.
- Can search for books based on title, author, or genre, and return up to 20 of those books.
Correctly implementing minimum functionality will warrant a passing grade, assuming some attempt at testing was made. This is a reminder that your code does not have to be functional to get testing points, so make sure to write tests for your code!
Some Final Notes
If this homework seems more complex than previous ones, know that is completely expected and normal! Most of this rather long handout is reading, and know that you’ve learned all the tools needed to complete the functions above, and that the staff is here for you to fill in any gaps. :) At the end of this project, you’ll get to learn several important skills that are used in the real world, including:
- Reading in data from a real-world source, and representing that data internally in Python
- Categorizing that data for use in an external program
- Keeping track of multiple changing data structures within a single program
As always, remember your resources, and feel free to come to TA hours for any confusions. Also remember to make use of the Conceptual Express line at hours for any questions that don’t directly involve your code! Y’all got this!
Theme Song
Game of Thrones Theme - Western Cover
Brown University CSCI 0111 (Spring 2020)
Do you have feedback? Fill out this form.
Homework 9: Book Bandit (Part One)
Due: Tuesday April 28th, 2020 at 9:00PM anywhere in the world.
For a summary of all handout corrections/frequently asked questions about this homework, please continue referring to this Campuswire post!
Setup and Handin
For this homework, we are providing you with some source code, including a stencil for
hw9_code.py
, in which you will write all of your code. We’ll also be providing you with a file that will contain all of your tests calledhw9_test.py
.A zip file containing the source code, including the stencil and testing file, can be downloaded here.When finished, hand in your
hw9_code.py
andhw9_test.py
into Gradescope. Make sure to use your anonymous account!The Assignment
Yee-haw! The tyrannical sheriff has gone rogue and started outlawing books left and right. You are a book-loving, entrepreneurial cowboy and you’ve accumulated a wide range of contraband books that you want to sell because it’s important literature.
There’s one problem though…
The cowboy book club doesn’t know which books they want to buy (they’re indecisive) and so it’s up to you to help them out (so you can reap the profits).
You must build a system so that:
(1) customers can browse, check out and buy those books (without the sheriff knowing),
(2) they can get recommendations for what books to buy,
(3) display this all on a website!
The website has already been handled for you, with details about how to run it described below. In this homework assignment, we’ll also be doing the recomendations part for you this time around, but don’t worry, you’ll get your turn at the rodeo! This is the first part of a two-part homework assignment that will lead to you completing what would have previously been the third project.
Resources We Provide
Click for more details about the website!
Home page
The home page shows a collection of books, organized by genre. There is no particular order to these books, they should be chosen randomly from the dataset every time the page is loaded.
Recommendations page
The recommendations page shows a list of books, sorted by how highly the system ranks those books for the user (for example, a book with 7 points comes before a book with 3 points; the point system is detailed below in the implementation details section).
Search page
The search page shows a list of books matching the user’s search query, sorted by the rating of the books in descending order (for example, 4.8 stars comes before 3.5 stars).
Viewing page
The book viewing page gives you more information about a book, and allows you to add the book to your cart.
Cart page
The cart displays all the books in the user’s cart, allowing them to remove individual books and purchase all the books in the cart.
Headers and footers
Each page has a header with links to useful pages and a search bar to look for books, and a footer that displays the book covers of the user’s previously purchased books.
Tasks
For this homework, you’ll be handling four major components of the backbone of our website:
Functions to Implement
In the stencil, we’ve instantiated four global lists. For this homework, you’ll be working with three of them:
book_master_list
,cart
, andpurchases
. You’ll be working on the following functions. Please read the information below carefully.Note: Functions with no output types don’t return anything.
setup():
Reads through the CSV file and creates a master list of books, b by ID (which you assign). The ID assigned to each Book should just be its index in the master list. For help figuring out how to read a CSV file, look at the example below. You can also find more examples in the solution to Lab 10.
CSV Processing Example
@dataclass class Posn: x : int y : int with open('books.csv') as f: lines = list(csv.reader(f)) for line in lines: my_posn = Posn(line[0], line[1])
get_cart() -> list:
Returns the current shopping cart of books.
get_book(ident: int) -> Book
Returns the book with ID
ident
(e.g. 1). If a book with the IDident
is not found, you can raise an error usingraise ValueError(<string>)
. For example:This might be helpful with debugging, and is also good coding practice. For more information about how to test errors, take a look at the Python testing guide.
add_book_to_cart(ident: int):
Adds the book identified by the index
ident
to the cart. You cannot have duplicates of books in a cart.remove_book_from_cart(ident: int):
Removes a book from the cart at index
ident
(e.g. 1) if it is in the cart.buy_books_in_cart():
Buys all books in the cart. You should call
update_recs
(a function we’ve provided; see Implementations We Provide below) on each book in your cart before moving it to the purchases. At the end, your cart should be empty! Also, books can be bought twice.search_books(query: str) -> list:
Given a query, return up to 20 of the books that contain the query in the title, author, or genre (case-insensitive in both directions). If there are fewer than 20 books that match, return all of those books.
make_genre_list(list) -> list:
Creates a list of lists (we’re calling it
genre_list
), with each sublist representing one genre. For this homework assignment, we only have 5 genres. These lists must come in the order we specify. Check out the Implementations We Provide section for more information aboutgenre_list
.get_purchases() -> list:
Returns all purchased books.
book_matches(query: str, book: Book)->bool
Checks to see if given the query if its in the book’s title, author, or genre.
Note: Throughout the stencil, you might see the keyword
global
sprinkled throughout the functions (i.e.,global book_master_list
). This tells Python that, even within the individual functions, they should be referencing the same list that was defined globally at the top.Note: You might notice that several of the methods above merely return one of the data structures we’re keeping track of globally! These get-functions might seem kind of useless at first, but these are important in making sure that external Python files (such as
app.py
, which will be used to run our website) can access the data contained inhw9_code.py
.If you take classes such as CS112 or CS18, you’ll learn more about the importance of get-functions!
Implementations We Provide
In the stencil code, there might be things that might seem unfamiliar. Please read the information below to get a better understanding of what’s going on.
Dataclasses: We’ve provided you with the Book and BookScorePair dataclasses. Please don’t modify these dataclasses.
Recommendations: In the code, we give you the implementations for
get_recommendations
,update_recs
, andupdate_recs_given_query_words
. These functions keep track of a recommendations score for each Book based on the user’s actions. These scores are kept track of using theBookScorePair
dataclass, which is described below. Please don’t modify these functions.BookScorePair:
@dataclass class BookScorePair: # ** do not modify this dataclass ** book : Book score : int
This dataclass represents a book and its respective recommendation score. How the user interacts with the website will change the score of the book. If you look at
update_recommendations
, you can see it in use. Since you are not implementing the recommendation scoring system in this homework, you don’t have to worry about this dataclass other than making not to delete it.Global variables/macros: In computer programs, it is common practice to use numbers to represent concepts to make code more readable. At the top of the stencil code, you’ll see some global variables, written in all caps, being set to numbers (ex:
ART = 0
).This allows us to use these words as numbers. This means we could do something like
ART + 5
to get 5, but we can also do something more useful: using these globals to index into lists. (In other words, if we had some list calledgenre_list
,genre_list[ART]
would return the 0th (first) element ofgenre_list
.) The globals we have provided specify what order the inner lists of yourgenre_list
should be in. If you do not follow this, books will be mismatched to their genres in the website!Running the code
The zip file we provide you contains all the files required for this assignment. Your code will go into
hw9_code.py
.To run the web app, you need to run
app.py
(also in that folder).app.py
contains the code to create what is called a “Flask application.” Flask is a Python package (similar to how datetime and dataclasses are Python packages) which allows you to make web servers.In PyCharm, run

app.py
. You should see something like this:While this is running, you will be able to go onto your web browser and go to the url that it gives you (
http://127.0.0.1:5000
above) and see the web app! This will only work on the computer that is running the application.You can only have one version of the web app running; if you try to run
app.py
twice, you will see an error message. You should be able to haveapp.py
running constantly; if you then make changes tohw9_code.py
, the app will automatically reload itself and you can refresh the website.If you are having a hard time running the web app, let the TAs know!
Testing Tips and Requirements
hw9_code.py
.get_book
, which you should test!)setup
, or anything we implement for you.make_genre_list
, it might be helpful to construct your own smaller data to test this function exhaustively. Try to think of several edge cases.book_master_list
, remember that thebook_master_list
will be empty unless we callsetup
or add to it ourselves. So, before we can test anytihng, we need to access it through theglobal
keyword, and then do something like this:Alternatively, we can also make our own smaller testing data:
We’ve provided an example of how you might do this in hw9_test.py.
Grading Requirements
Minimum Functionality:
Full Functionality:
Correctly implementing minimum functionality will warrant a passing grade, assuming some attempt at testing was made. This is a reminder that your code does not have to be functional to get testing points, so make sure to write tests for your code!
Some Final Notes
If this homework seems more complex than previous ones, know that is completely expected and normal! Most of this rather long handout is reading, and know that you’ve learned all the tools needed to complete the functions above, and that the staff is here for you to fill in any gaps. :) At the end of this project, you’ll get to learn several important skills that are used in the real world, including:
As always, remember your resources, and feel free to come to TA hours for any confusions. Also remember to make use of the Conceptual Express line at hours for any questions that don’t directly involve your code! Y’all got this!
Theme Song
Game of Thrones Theme - Western Cover