Practice: kiosk inventory

Config, module, tests, and a report for a Nairobi kiosk.

Load config and inventory, put pricing in a module, test it, write a report. Download config.json and inventory.csv from the banner and Add files, or let the first block create them.

Goal

Produce report.csv for a Nairobi kiosk and a passing unittest suite.

Seed files (skip if you already attached the banner files)

from pathlib import Path

Path("config.json").write_text(
    '{"city": "Nairobi", "tax": 0.16, "currency": "KES"}\n',
    encoding="utf-8",
)
Path("inventory.csv").write_text(
    "product,units,price\nA,12,10.5\nB,7,22.0\nC,2,31.0\n",
    encoding="utf-8",
)
print("wrote config.json and inventory.csv")

Module, tests, report

import csv
import json
import unittest
from pathlib import Path

Path("kiosk.py").write_text(
    '''def line_total(units, price, tax):
    if units < 0 or price < 0:
        raise ValueError("units and price must be >= 0")
    return round(float(units) * float(price) * (1 + tax), 2)

def city_label(city):
    return str(city or "").strip().title()
''',
    encoding="utf-8",
)

import kiosk

cfg = json.loads(Path("config.json").read_text(encoding="utf-8"))
tax = float(cfg["tax"])
city = kiosk.city_label(cfg["city"])

rows = []
with Path("inventory.csv").open(encoding="utf-8", newline="") as handle:
    for row in csv.DictReader(handle):
        total = kiosk.line_total(row["units"], row["price"], tax)
        rows.append(
            {
                "product": row["product"],
                "units": row["units"],
                "price": row["price"],
                "total": f"{total:.2f}",
            }
        )

grand = round(sum(float(r["total"]) for r in rows), 2)
print(city, cfg["currency"], "lines", len(rows), "grand", grand)

class KioskTests(unittest.TestCase):
    def test_line(self):
        self.assertEqual(kiosk.line_total(2, 10, 0.16), 23.2)

    def test_city(self):
        self.assertEqual(kiosk.city_label("  nairobi "), "Nairobi")

    def test_three_products(self):
        self.assertEqual(len(rows), 3)

suite = unittest.defaultTestLoader.loadTestsFromTestCase(KioskTests)
result = unittest.TextTestRunner(verbosity=2).run(suite)
print("ok" if result.wasSuccessful() else "failed")

out = Path("report.csv")
with out.open("w", encoding="utf-8", newline="") as handle:
    writer = csv.DictWriter(handle, fieldnames=["product", "units", "price", "total"])
    writer.writeheader()
    writer.writerows(rows)
print(out.read_text(encoding="utf-8"))

Click on report.csv. You should see three product lines for Nairobi.

You should see

A tidy city label, three priced rows, a passing suite, and a downloadable CSV. That is the shape: config, module, tests, output.