Skip to main content

Packaging & a production capstone

Level 4: Level 4: Engineeringhard25 minpackagingcapstonetype-hintstesting

Build a typed, tested, packaged order service that integrates the whole track.

Packaging: the last mile

Your code only creates value once someone else can run it. Packaging is how you hand a colleague pip install orders instead of a folder and a prayer. A published package pins your version, declares its dependencies, and installs the same way on every machine, which is exactly what CI, Docker images, and teammates depend on.

What a wheel actually is

A wheel (.whl) is a zip of your importable code plus metadata, named to a fixed convention. pyproject.toml is the single source of truth: the [project] table declares name, version, requires-python, and dependencies, plus a dev extra for pytest, ruff, and mypy. A [build-system] table names the build backend that turns the project into artifacts.

uv build        # writes dist/orders-1.0.0.tar.gz and dist/orders-1.0.0-py3-none-any.whl
uv publish      # uploads those artifacts to a package index (PyPI)

The py3-none-any tag means pure Python, any interpreter, any OS. Nothing to compile.

Check yourself
A colleague points out that their package still ships a setup.py and installs perfectly well. What is the real argument for pyproject.toml?

The production checklist

A shippable library is structured (a clean package with clear entry points), typed (hints on the public API so callers and mypy know the contract), validated (untrusted input parsed into typed values at the boundary), and tested (pytest over the real cases, run in CI). Your capstone hits all four.

Parsing at the boundary

Raw input is not your model. Each raw order arrives as a dict whose "amount" is a string, so summarize must parse it into a number before it can do arithmetic:

def summarize(raw_orders):
    paid = [o for o in raw_orders if o["paid"]]
    revenue = round(sum(float(o["amount"]) for o in paid), 2)
    return {"count": len(raw_orders), "paid": len(paid), "revenue": revenue}

rows = [{"amount": "10.0", "paid": True}, {"amount": "5.0", "paid": False}]
print(summarize(rows))
# {'count': 2, 'paid': 1, 'revenue': 10.0}

count is every order, paid is how many cleared, and revenue sums only the paid amounts. In the capstone, a read-only parse_order does this coercion for you, turning each raw dict into a typed Order.

Check yourself
Each line total is unit_price times quantity times 1.0825 for tax, so the raw amounts carry many decimals. To keep the running total tidy you round each one to cents before adding it. Ten thousand orders later, how does your revenue compare to summing first and rounding once?

Pitfalls

  • int("10.0") raises ValueError because "10.0" is not an integer literal. Parse decimal strings with float("10.0").
  • Round once, at the very end. Sum first, then round(total, 2). Floats cannot hold most decimals exactly, so 0.1 + 0.2 == 0.3 is False (it is 0.30000000000000004), and rounding after each addition compounds that error.
Check yourself
A refund calculation lands on exactly 0.125 and you write round(0.125, 2). What comes back?

Interview nuance: float cannot represent most base-10 fractions exactly, so a long chain of price additions drifts. round(total, 2) cleans up the display but not the stored value, and round uses banker's rounding, so round(0.125, 2) gives 0.12 (rounded to even), not 0.13. Production money code stores integer cents or uses Decimal; reach for float only when a tiny rounding error is acceptable.

Check yourself
You are designing the orders table and the matching Python model for a real payments service. How should an amount be stored?
Worked example (Python)
from dataclasses import dataclass


@dataclass
class Order:
    id: int
    amount: float
    paid: bool


orders = [Order(1, 10.0, True), Order(2, 5.0, False)]
paid = [o for o in orders if o.paid]
print({"count": len(orders), "paid": len(paid), "revenue": round(sum(o.amount for o in paid), 2)})

Apply

Your turn

The task this lesson builds to.

Warm-up (one file): implement summarize(raw_orders). Each raw order is a dict with "amount" (a numeric string) and "paid" (a bool). Return {"count": <all>, "paid": <paid>, "revenue": <sum of paid amounts, rounded to 2>}.

For one paid "10.0" and one unpaid "5.0", revenue is 10.0.

3 hints and 3 automated checks are waiting in the workspace.

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Capstone: implement summarize(raw_orders) in orders/report.py. Parse each raw order with the read-only parse_order (into a typed Order), then return {"count", "paid", "revenue"} where revenue sums paid orders' amounts, rounded to 2 decimals. Some tests are hidden.

3 hints and 2 automated checks are waiting in the workspace.