A capstone statement is long. The order-model capstone has more than twenty rules, and its tests check all of them at once. If you write the whole thing and then press Run, a failing case tells you which value in the report is wrong. It does not tell you which rule you broke.
So build one part at a time. Pick a small rule, write the code for it, and
check it with a few assert lines before you go on. Here is a first check
for the import-rules capstone, where an entry such as "pricing.domain"
covers that module and every module inside it:
def covers(entry: str, module: str) -> bool:
return module == entry or module.startswith(entry + ".")
assert covers("pricing.domain", "pricing.domain")
assert covers("pricing.domain", "pricing.domain.rules")
assert not covers("pricing.domain", "pricing.domain_extra")
The third assert catches a real bug. A plain module.startswith(entry) would
say that pricing.domain covers pricing.domain_extra.
Work through a capstone in this order
- Read the example and the "What the driver checks" section first. Together they show what your finished code returns.
- Read the starter. It supplies the types, the exceptions and the test
driver,
solve. Leavesolveas it is. - Write one part, and check it with a few
assertlines in a scratch file on your own computer. - Run
mypy --stricton your file after each part. A type error is easier to fix while the new code is small. On the site, Run skips mypy and Submit runs it. - Press Run once every part exists, and compare the report key by key with the expected output.
- Before you submit, read the edge-case rules once more. Submit also runs hidden test cases, and they test those rules.
What each capstone builds on
Each capstone uses ideas from four earlier items. If you get stuck on one part, go back to the item it comes from. The capstones do not depend on each other, so you can do them in any order.
Capstone: Give Each Upload State Its Own Type builds on:
- Count Visited Cells with a Frozen Dataclass, for frozen dataclasses.
- Let mypy Catch a Missing Case with assert_never, for
matchwithassert_never. - Type a Lookup with a Default Using Overloads, which checks return types with
assert_type. - Clean Up
type: ignoreComments, for ignore comments that mypy reports as unused.
Capstone: Check a Package's Layer and Import Rules builds on:
- Describe a Dictionary's Keys with TypedDict, for
TypedDict. - Make mypy Report an Unhandled Event with assert_never, for making mypy check that you handle every case.
- Check That Imports Follow Your Layers, which checks direct imports between layers.
- Find Import Chains That Reach a Forbidden Package, which follows imports through other modules.
Capstone: Build an Immutable Order Model from Untrusted Data builds on:
- Type-Check a Custom Dataclass Decorator with dataclass_transform, for the decorator.
- Compute Cents from an Amount with
__post_init__, for a field computed from the others. - Update a Frozen Record with replace(), for changing a frozen record by making a new one.
- Parse Untrusted JSON into a Dataclass, for checking outside data and naming the bad field.
Capstone: Extend the Worker Pool to Keep Going After Failures builds on:
- Capstone: Build an Async Worker Pool with Retries and Clean Shutdown, the concurrency track's capstone. This one changes three of its rules, so solve it first.
- Collect Every Failure in a Batch, for
ExceptionGroup. - Build a Request ID That Follows Tasks and Threads, for
contextvars. - Release a Connection However the Stream Ends, for
aclosing.
Capstone: Fix Five Performance Problems in an Order Pipeline builds on:
- Use a Set for Lookups and a Deque for Queues, for fast membership checks.
- Give Each Object Its Own Cache, for a cache that does not keep objects alive.
- Build Strings with join and Bytes with bytearray, for joining parts once.
- Find Memory Growth with tracemalloc, for measuring memory.
Check your understanding Why check each part with its own assert lines before you press Run? Show answer Hide answer
Run compares the whole report, and one wrong value in it can come from any of
several parts. An assert on one part, with an input small enough to work out
by hand, fails on the rule you broke. You also fix the bug while the new code
is small, before other parts depend on it.