Code editing task: bookkeeping
Topic: Misc; change kind: adaptive

Original code:
class Yarn:
    """Represents the yarns that a yarn store sells"""
    
    def __init__(self, purchase_price: int, sell_price: int, color: str):
        self.purchase_price = purchase_price
        self.sell_price = sell_price
        self.color = color

class BankAccount:
    """Represents the bank account of this yarn store"""

    def __init__(self, balance: int):
        self.balance = balance

    def reduce_balance(self, quantity: int):
        """Reduces balance of this account if possible"""
        if quantity > self.balance:
            raise ValueError
        else:
            self.balance -= quantity
    
    def add_balance(self, quantity: int):
        """Adds to this account's balacne"""
        self.balance += quantity

    
    def get_balance(self):
        """Returns the balance of this account"""
        return self.balance

class WareHouse:
    """Represents a warehouse that stores the yarn stock of this yarn store."""
    
    def __init__(self):
        self.stock = {}

    def stock_of(self, item: Yarn):
        """Gets the stock of the yarn given"""
        if item not in self.stock:
            raise ValueError
        else:
            return self.stock[item]
        
    def add_stock(self, items: dict[Yarn, int]):
        """Adds stock to this warehouse"""
        for item, quant in items.items():
            if item in self.stock:
                self.stock[item] += quant
            else:
                self.stock[item] = quant
    
    def reduce_stock(self, items: dict[Yarn, int]):
        """Reduces the stock of this warehouse"""
        for item, quant in items.items():
            if item in self.stock and self.stock[item] >= quant:
                self.stock[item] -= quant
            else:
                raise ValueError

class Store:
    
    def __init__(self, starting_balance: int):
        self.bank = BankAccount(starting_balance)
        self.warehouse = WareHouse()

    def buy_yarn(self, order: dict[Yarn, int], price: int):
        """Buy the quantity of yarn specified by the order"""
        self.warehouse.add_stock(order)
        self.bank.reduce_balance(price)
    
    def sell_yarn(self, order: dict[Yarn, int], price: int):
        """Sell the quantity of yarn specified by the order"""
        self.warehouse.reduce_stock(order)
        self.bank.add_balance(price)

Instruction (descriptive):
Edit the `buy_yarn` and `sell_yarn` methods in the `Store` class to calculate the price of the order depending on whether its a purchase or a sale, rather than taking in an argument that specifies the total cost of the order.

Instruction (lazy):
Edit the `buy_yarn` and `sell_yarn` methods in the `Store` class to calculate the price of the order rather than taking in an argument for it.

Edited code:
class Yarn:
    """Represents the yarns that a yarn store sells"""
    
    def __init__(self, purchase_price: int, sell_price: int, color: str):
        self.purchase_price = purchase_price
        self.sell_price = sell_price
        self.color = color

class BankAccount:
    """Represents the bank account of this yarn store"""

    def __init__(self, balance: int):
        self.balance = balance

    def reduce_balance(self, quantity: int):
        """Reduces balance of this account if possible"""
        if quantity > self.balance:
            raise ValueError
        else:
            self.balance -= quantity
    
    def add_balance(self, quantity: int):
        """Adds to this account's balacne"""
        self.balance += quantity

    
    def get_balance(self):
        """Returns the balance of this account"""
        return self.balance

class WareHouse:
    """Represents a warehouse that stores the yarn stock of this yarn store."""
    
    def __init__(self):
        self.stock = {}

    def stock_of(self, item: Yarn):
        """Gets the stock of the yarn given"""
        if item not in self.stock:
            raise ValueError
        else:
            return self.stock[item]
        
    def add_stock(self, items: dict[Yarn, int]):
        """Adds stock to this warehouse"""
        for item, quant in items.items():
            if item in self.stock:
                self.stock[item] += quant
            else:
                self.stock[item] = quant
    
    def reduce_stock(self, items: dict[Yarn, int]):
        """Reduces the stock of this warehouse"""
        for item, quant in items.items():
            if item in self.stock and self.stock[item] >= quant:
                self.stock[item] -= quant
            else:
                raise ValueError

class Store:
    
    def __init__(self, starting_balance: int):
        self.bank = BankAccount(starting_balance)
        self.warehouse = WareHouse()

    def buy_yarn(self, order: dict[Yarn, int]):
        """Buy the quantity of yarn specified by the order"""
        self.warehouse.add_stock(order)
        self.bank.reduce_balance(self.calculate_cost(order, True))
    
    def sell_yarn(self, order: dict[Yarn, int]):
        """Sell the quantity of yarn specified by the order"""
        self.warehouse.reduce_stock(order)
        self.bank.add_balance(self.calculate_cost(order, False))

    def calculate_cost(self, order: dict[Yarn, int], is_purchase: bool):
        """Calcualtes the cost of this order, depending on if we are buying or selling yarn"""
        total = 0
        for item in order:
            if is_purchase:
                total += item.purchase_price * order[item]
            else:
                total += item.sell_price * order[item]
        return total

Tests:
### START TESTS ###
if True:  # pragma: no cover
    y1 = Yarn(2, 3, "black")
    y2 = Yarn(4, 9, "yellow")
    y3 = Yarn(1, 4, "blue")
    y4 = Yarn(2, 5, "red")
    y5 = Yarn(3, 3, "white")

    s = Store(100)

    # purchase price of this should be 62
    stock = {
        y1: 5,
        y2: 5,
        y3: 10,
        y4: 5,
        y5: 4
    }

    # sell price of this should be 58
    sold = {
        y1: 2,
        y2: 1,
        y3: 8,
        y4: 2,
        y5: 3
    }

    purchase = {
        y5: 10
    }

    # testing bank account

    b = BankAccount(100)

    b.reduce_balance(10)
    assert b.get_balance() == 90

    b.add_balance(200)
    assert b.get_balance() == 290

    try:
        b.reduce_balance(300)
        assert False
    except ValueError:
        pass

    # testing warehouse

    w = WareHouse()

    try:
        w.stock_of(y1)
        assert False
    except ValueError:
        pass

    w.add_stock(stock)
    w.add_stock(stock)

    assert w.stock_of(y1) == 10
    assert w.stock_of(y2) == 10
    assert w.stock_of(y3) == 20
    assert w.stock_of(y4) == 10
    assert w.stock_of(y5) == 8

    try:
        w.reduce_stock(purchase)
        assert False
    except ValueError:
        pass

    # testing yarn store

    s.buy_yarn(stock)
    assert s.warehouse.stock_of(y4) == 5
    assert s.warehouse.stock_of(y3) == 10
    assert s.bank.get_balance() == 38

    s.sell_yarn(sold)
    assert s.bank.get_balance() == 104
    assert s.warehouse.stock_of(y1) == 3
    assert s.warehouse.stock_of(y2) == 4
    assert s.warehouse.stock_of(y3) == 2
    assert s.warehouse.stock_of(y4) == 3
    assert s.warehouse.stock_of(y5) == 1