1 The Problem
We want an inventory system: track products and quantities, restock (add stock), sell (remove stock, but never below zero), and report which items are low. It teaches modelling a collection of items with business rules and reporting on them — the core of any stock, warehouse, or store system.
2 How to Think About It
Think about the operations and rules, before any code:
3 The Build — explained part by part
Here is the complete inventory system as a class. Each part is explained below.
import json
import os
class Inventory:
def __init__(self, filename="inventory.json"):
self.filename = filename
self.items = self._load()
def _load(self):
if os.path.exists(self.filename):
return json.load(open(self.filename))
return {}
def _save(self):
json.dump(self.items, open(self.filename, "w"))
def restock(self, item, quantity):
self.items[item] = self.items.get(item, 0) + quantity
self._save()
def sell(self, item, quantity):
if self.items.get(item, 0) < quantity:
raise ValueError(f"Not enough {item} in stock")
self.items[item] -= quantity
self._save()
def low_stock(self, threshold=5):
return [item for item, qty in self.items.items() if qty < threshold]
if __name__ == "__main__":
inv = Inventory()
inv.restock("apples", 10)
inv.sell("apples", 7)
print("Low stock:", inv.low_stock())
self.items.get(item, 0) — look up a quantity, defaulting to 0 for items not yet stocked. This avoids errors on new products.
restock — add to the current quantity (or start from 0), then save.
sell — the business rule: refuse to sell more than is in stock by raising an error. Stock can never go negative.
low_stock(threshold=5) — a report: return every item whose quantity is below the threshold, using a list comprehension. Default threshold of 5, overridable.
_load / _save — the leading underscore signals these are internal helpers, not meant to be called from outside. Every change is saved immediately.
sell and raise if there is not enough.self.items[item] directly for a new item — KeyError.self.items.get(item, 0) so new items default to 0._save() after restock and sell.4 Test & Prove Each Part
We test restocking, the no-oversell rule, and the low-stock report.
import pytest
class Inventory:
def __init__(self):
self.items = {}
def restock(self, item, quantity):
self.items[item] = self.items.get(item, 0) + quantity
def sell(self, item, quantity):
if self.items.get(item, 0) < quantity:
raise ValueError("Not enough stock")
self.items[item] -= quantity
def low_stock(self, threshold=5):
return [i for i, q in self.items.items() if q < threshold]
def test_restock():
"""Restocking adds quantity."""
inv = Inventory()
inv.restock("apples", 10)
assert inv.items["apples"] == 10
def test_sell():
"""Selling reduces quantity."""
inv = Inventory()
inv.restock("apples", 10)
inv.sell("apples", 3)
assert inv.items["apples"] == 7
def test_oversell_refused():
"""Selling more than stock raises an error."""
inv = Inventory()
inv.restock("apples", 2)
with pytest.raises(ValueError):
inv.sell("apples", 5)
def test_low_stock():
"""Items below threshold are reported."""
inv = Inventory()
inv.restock("apples", 2)
inv.restock("bread", 20)
assert inv.low_stock(5) == ["apples"]
Run with pytest -v. As with the bank, we test that bad actions (overselling) are refused, not just that good ones work. The low-stock test proves the report logic is correct.
5 The Interface
Returns
["apples", "milk"]6 Run It & Automate It
python3 inventory.pyRestock and sell items, then check what is low. Stock is saved in
inventory.json.Jenkins runs the tests automatically — each line explained below.
Low stock: ['apples']KeyError when selling a new item..get(item, 0) so unknown items are treated as zero stock.// Jenkinsfile — automated tests on every change.
pipeline {
agent any
stages {
stage('Get the code') { steps { checkout scm } } // download the code
stage('Install') { steps { sh 'python3 -m venv venv && . venv/bin/activate && pip install pytest' } } // test tool
stage('Test') { steps { sh '. venv/bin/activate && pytest -v' } } // run every test
}
post {
success { echo 'All tests passed.' }
failure { echo 'A test failed — look above.' }
}
}
- Prices and value. Track price per item and report total inventory value. (Teaches: richer records.)
- Auto-reorder. Flag items to reorder and suggest quantities. (Teaches: business logic.)
- Sales log. Record every sale with a timestamp. (Teaches: history tracking.)