Final Code

MOCK FINAL EXAM – SET 1

Theme: Library System (Books & Borrowing)

Task 1 – Abstract Class LibraryItem

Create an abstract class LibraryItem with:

  • Non-public attributes: _title, _year_published

  • Getters/setters with validation:

    • title – cannot be empty string

    • year_published – must be between 1450 and current year (use 2026 as current)

  • Raise ValueError for invalid values

  • Abstract method: get_info()


Task 2 – Class Book inherits from LibraryItem

Add non-public attributes:

  • _isbn (string)

  • _borrow_history (list of integers representing days borrowed per transaction)

Implement:

  • Getters for ISBN and borrow history

  • get_info() returns formatted string

  • average_borrow_duration() – average days per borrowing

  • Override __iadd__ – adds a valid borrow duration (integer > 0) to history

  • Override __len__ – returns number of borrow transactions


Task 3 – CSV Processing

CSV file (library_borrows.csv):

text

isbn;title;year;days_borrowed
978-3-16-148410-0;Python Basics;2020;14
978-0-13-468599-1;Data Structures;2019;21
978-3-16-148410-0;Python Basics;2020;7
978-0-596-52068-7;Learning Java;2018;30
978-0-13-468599-1;Data Structures;2019;10
978-3-16-148410-0;Python Basics;2020;28

Read CSV, group by ISBN, create Book objects, accumulate borrow histories.


Task 4 – JSON Processing

Same data as JSON (library_borrows.json):

json

[
  {"isbn": "978-3-16-148410-0", "title": "Python Basics", "year": 2020, "days_borrowed": 14},
  {"isbn": "978-0-13-468599-1", "title": "Data Structures", "year": 2019, "days_borrowed": 21},
  {"isbn": "978-3-16-148410-0", "title": "Python Basics", "year": 2020, "days_borrowed": 7},
  {"isbn": "978-0-596-52068-7", "title": "Learning Java", "year": 2018, "days_borrowed": 30},
  {"isbn": "978-0-13-468599-1", "title": "Data Structures", "year": 2019, "days_borrowed": 10},
  {"isbn": "978-3-16-148410-0", "title": "Python Basics", "year": 2020, "days_borrowed": 28}
]

Repeat grouping process from Task 3.


Task 5 – Output

Print each book:

text

Title: Python Basics, borrows: 3, average days: 16.33
Title: Data Structures, borrows: 2, average days: 15.50
Title: Learning Java, borrows: 1, average days: 30.00

Task 6 – Unit Tests

Write unittest tests for:

  1. LibraryItemyear_published setter:

    • Valid: 2000

    • Invalid: 1400 (too old), 2030 (future)

  2. Book.__iadd__:

    • Valid: book + 15

    • Invalid: book + -5 (negative days)

    • Invalid: book + "ten" (wrong type)

final.py:

#mock final exam set 1 - Library system

from abc import ABC, abstractmethod
import csv
import json

#task 1
class LibraryItem(ABC):
    def __init__(self, title, year_published):
        self._title = title
        self._year_published = year_published

    def get_title(self):
        return self._title
    def get_year_published(self):
        return self._year_published

"""
INCORRECT
    def set_title(self, title):
        try:
            if title == "":
                print("Title cannot be empty")
            else:
                self._title = title
        raise ValueError("Title cannot be empty")   
   
"""
#CORRECT
def set_title(self, title):
       if not title:
           raise ValueError("Title cannot be empty")
       self._title = title

"""
INCORRECT
    def set_year_published(self, year_published):
        try:
            if 1450<= year_published <=2026:
                self._year_published = year_published
            else:
                print("Year published is out of range")
        raise ValueError("Year published is out of range")
"""
def set_year_published(self, year_published):
    if not 1450<=year_published<=2026:
        raise ValueError("Year published cannot be empty")
    self._year_published = year_published

    @abstractmethod
    def get_info(self):
        pass

#task 2
class Book(LibraryItem):
    def __init__(self, title, year_published, isbn):
        super().__init__(title, year_published)
        self._isbn = isbn
        self._borrow_history = []

    def get_isbn(self):
        return self._isbn

    def get_borrow_history(self):
        return self._borrow_history

    def get_info(self):
        return f"{self._title} is published on {self._year_published}, was borrowed on {self._borrow_history}"

    def average_borrow_duration(self):
        return sum(self._borrow_history) / len(self._borrow_history)
"""
INCORRECT
    def __iadd__(self, other):
        try:
            if self._borrow_history is int and self._borrow_history > 0:
                return self._borrow_history.append(other)
            else:
                self._borrow_history = other._borrow_history
        raise ValueError("Must be more than 0")
"""
def __iadd__(self, other):
    if not isinstance(other, int) or other <=0:
        raise ValueError("Must be more than 0")
    self._borrow_history.append(other)
    return self

    def __len__(self):
        return len(self._borrow_history)

#task 3

def ex1():
    books = {}
    with open("library_borrows.csv") as file:
        reader = csv.reader(file, delimiter=';')
        next(reader)
        for row in reader:
            isbn = row[0]
            title = row[1]
            year_published = int(row[2])
            borrow_history = int(row[3])

            if isbn not in books:
                books[isbn] = Book(title, year_published) #create the Book

            books[isbn] += borrow_history
    return books


            """
            isbn_group = list(filter(_isbn)) #don't know/remember how to group by isbn
            book1= "978-0-13-468599-4;Data Analysis;2021;10" #i guess this is how we create Book objects

            #accumulate borrow histories - don't even know how to attempt
"""

#task 4 - json processing - to be frank, i don't know anything in python about how to wrok with json, especially
#how to pivot from csv to json, please show me full code, functionalities

def ex1():
    books = {}
    with open("library_borrows.json") as file:
        reader = json.load(file)
        for row in reader:
            isbn = row["isbn"]
            title = row["title"]
            year_published = int(row["year_published"])
            borrow_history = int(row["borrow_history"])
            if isbn not in books:
                books[isbn] = Book(title, year_published, isbn)
            books[isbn] += borrow_history
        return books

#task 5 - output
for book in books.values():
    print(f"Title: {book._title}, borrows: {book._borrow_history}, "
          f"average days: {book.average_borrow_duration}")

test_final.py

import unittest
from final2 import Book

#task 6 - unit tests
class MyTestCase(unittest.TestCase):
    def setUp(self):
        self.book = Book("Python Basics", 2020, "978-3-16-148410-0")

#again - i don't remember syntax for unit tests, don't even know how to start and logic for writing it
#updated

    def test_year_validation(self):
        self.book.set_year_published(2000)
        self.assertEqual(self.book.get_year_published(), 2000)


    def test_year_failure(self):
        with self.assertRaises(ValueError):
            self.book.set_year_published(1400)
        with self.assertRaises(ValueError):
            self.book.set_year_published(2030)

    def test_iadd_valid(self):
        self.book +=15
        self.assertEqual(len(self.book), 1)
        self.assertEqual(self.book.get_borrow_history(), [15])

    def test_iadd_failure(self):
        with self.assertRaises(ValueError):
            self.book += -5
        with self.assertRaises(ValueError):
            self.book += "ten"



if __name__ == '__main__':
    unittest.main()

MOCK FINAL EXAM – SET 2

Theme: E-commerce (Products & Reviews)

Task 1 – Abstract Class Product

Create abstract class Product with:

  • Non-public attributes: _name, _price

  • Getters/setters with validation:

    • name – non-empty, at least 3 characters

    • price – must be > 0 (float or int)

  • Raise ValueError for violations

  • Abstract method: get_details()


Task 2 – Class ReviewedProduct inherits from Product

Add non-public attributes:

  • _sku (string, stock keeping unit)

  • _ratings (list of integers 1–5)

Implement:

  • Getters for SKU and ratings

  • get_details() returns product info

  • average_rating() – mean of ratings

  • Override __iadd__ – adds valid rating (1–5 integer only)

  • Override __len__ – number of ratings


Task 3 – CSV Processing

CSV file (product_reviews.csv):

text

sku;name;price;rating
SKU100;Wireless Mouse;25.99;5
SKU200;Mechanical Keyboard;89.50;4
SKU100;Wireless Mouse;25.99;3
SKU300;USB Cable;12.99;5
SKU200;Mechanical Keyboard;89.50;5
SKU100;Wireless Mouse;25.99;4
SKU200;Mechanical Keyboard;89.50;2

Read CSV, group by SKU, create ReviewedProduct objects, accumulate ratings.


Task 4 – JSON Processing

Same data as JSON (product_reviews.json):

json

[
  {"sku": "SKU100", "name": "Wireless Mouse", "price": 25.99, "rating": 5},
  {"sku": "SKU200", "name": "Mechanical Keyboard", "price": 89.50, "rating": 4},
  {"sku": "SKU100", "name": "Wireless Mouse", "price": 25.99, "rating": 3},
  {"sku": "SKU300", "name": "USB Cable", "price": 12.99, "rating": 5},
  {"sku": "SKU200", "name": "Mechanical Keyboard", "price": 89.50, "rating": 5},
  {"sku": "SKU100", "name": "Wireless Mouse", "price": 25.99, "rating": 4},
  {"sku": "SKU200", "name": "Mechanical Keyboard", "price": 89.50, "rating": 2}
]

Repeat grouping.


Task 5 – Output

Print each product:

text

Name: Wireless Mouse, ratings: 3, average: 4.00
Name: Mechanical Keyboard, ratings: 3, average: 3.67
Name: USB Cable, ratings: 1, average: 5.00

Task 6 – Unit Tests

Test:

  1. Productprice setter:

    • Valid: 29.99

    • Invalid: 0, -10

  2. ReviewedProduct.__iadd__:

    • Valid: product + 5

    • Invalid: product + 6 (too high), product + 0 (too low)

final3.py:

#MOCK FINAL EXAM – SET 2 Theme: E-commerce (Products & Reviews)
import csv
from abc import ABC, abstractmethod
import json

#task1
class Product(ABC):
    def __init__(self, name, price):
        self._name = name
        self._price = price

    def get_name(self):
        return self._name
    def get_price(self):
        return self._price

    def set_name(self, name):
        if not name or len(name)<3:
            raise ValueError("Invalid name")
        self._name = name

    def set_price(self, price):
        if not isinstance(price, int) or not isinstance(price, float):
            raise ValueError('Price must be a positive integer')
        self._price = price

    @abstractmethod
    def get_details(self):
        pass
#task 2
class ReviewedProduct(Product):
    def __init__(self, name, price, sku):
        super().__init__(name, price)
        self._sku = sku
        self._ratings = []

    def get_sku(self):
        return self._sku
    def get_ratings(self):
        return self._ratings

    def get_details(self):
        return f"{self._name} costs {self._price}. There's {len(self._ratings)} ratings and {len(self._sku)} units in stock"

    def average_rating(self):
        return sum(self._ratings)/len(self._ratings)

    def __iadd__(self, other):
        if self.other <=1 or self.other >=5:
            raise ValueError("The other must be greater than or equal to 5")
        elif not isinstance(other, int):
            raise ValueError('The other must be an integer')
        else:
            self._ratings.append(other)
        return self

    def __len__(self):
        return len(self._ratings)

#task 3
def ex1():
    reviewed = {}
    with open('product_reviews.csv') as file:
        next(file)
        reader = csv.reader(file, delimiter = ';')
        for row in reader:
            name = row[1]
            price = float(row[2])
            sku = row[0]
            ratings = int(row[3])
            if sku not in reviewed:
                reviewed[sku] = ReviewedProduct(name, price, sku)
            reviewed[sku] += ratings
        return reviewed
#task 4
def ex2():
    reviewed = {}
    with open('product_reviews.json') as file:
        reader = json.load(file)
        for row in reader:
            name = row["name"]
            price = float(row["price"])
            sku = row["sku"]
            rating = int(row["ratings"])
            if sku not in reviewed:
                reviewed[sku] = ReviewedProduct(name, price, sku)
            reviewed[sku] += rating
        return reviewed

#task 5
def print_products(reviewed):
    for review in reviewed.values():
        print(f"Name:{review.get_name}, rating: {len(review)}, average: {review.average_rating()}")
  

test_final3.py:

import unittest
from final3 import *

#task 6
class MyTestCase(unittest.TestCase):
    def setUp(self):
        self.product = ReviewedProduct("Wireless Kitten",25.99, "SKU100")

    def test_get_price_success(self):
        self.product.set_price(29.98)
        self.assertEqual(self.product.get_price(), 29.99)

    def test_get_price_zero(self):
        with self.assertRaises(ValueError):
            self.product.set_price(0)

    def test_get_price_negative(self):
        with self.assertRaises(ValueError):
            self.product.set_price(-1)

    def test_iadd_reviewed_product_success(self):
        self.product +=5
        self.assertEqual(len(self.product), 1)
        self.assertEqual(self.product.get_ratings(), [5])

    def test_iadd_reviewed_product_failure(self):
        with self.assertRaises(ValueError):
            self.product +=6
    def test_iadd_reviewed_product_zero(self):
        with self.assertRaises(ValueError):
            self.product +=0

if __name__ == '__main__':
    unittest.main()