Typestate in Python APIs¶
Page Maps¶
graph LR
family["Python Programming"]
program["Python Object-Oriented Programming"]
section["State Validation Typestate"]
page["Typestate in Python APIs"]
capstone["Capstone evidence"]
family --> program --> section --> page
page -.applies in.-> capstone
flowchart LR
orient["Orient on the page map"] --> read["Read the main claim and examples"]
read --> inspect["Inspect the related code, proof, or capstone surface"]
inspect --> verify["Run or review the verification path"]
verify --> apply["Apply the idea back to the module and capstone"]
Read the first diagram as a placement map: this page is one concept inside its parent module, not a detached essay, and the capstone is the pressure test for whether the idea holds. Read the second diagram as the working rhythm for the page: name the problem, study the example, identify the boundary, then carry one review question forward.
Why this lesson matters¶
It is not enough to know that an object has states. The API should help callers do the right thing for the current state.
If callers can ask for every operation all the time, typestate remains only a comment in the programmer’s head.
This lesson is about making legal and illegal operations visible in ordinary Python, even without a fancy type system.
The core design idea¶
A typestate-aware API tries to make misuse harder by shaping the public surface around state.
That can mean:
- different methods for different state objects
- explicit transition methods
- narrow runtime guards at the right boundaries
- separate wrappers or types when the states are meaningfully different
The point is not perfection. The point is fewer nonsense calls and clearer reviewable intent.
Why one baggy API is weak¶
A single class with every method always present often creates this problem:
- callers can see and call actions that are currently illegal
- mistakes are discovered late
- state rules are repeated in several places
That design hides the lifecycle contract instead of expressing it.
Practical enforcement moves in Python¶
Useful enforcement moves include:
- returning a new state-specific object after a transition
- limiting certain methods to state-specific classes
- placing runtime guards in one clear place instead of everywhere
- designing functions to accept only the right state-bearing abstraction
These are plain design tools, not advanced type theory.
When runtime guards are enough¶
Sometimes a strong runtime guard is enough if:
- the lifecycle is simple
- illegal operations are rare and easy to explain
- a heavier state split would add more noise than value
But if misuse is common or the state differences are central, stronger API separation is usually worth it.
What to avoid¶
- one giant class with dozens of "not allowed in this state" branches
- repeating the same guard in many methods
- pretending a status field alone makes the API safe
- adding state-specific types only as labels while keeping the same weak surface
Typestate should reduce ambiguity, not merely rename it.
Review checklist¶
| Question | Good sign |
|---|---|
| do illegal operations become harder to call by accident? | yes |
| are transition points explicit? | yes |
| is state enforcement concentrated instead of duplicated everywhere? | yes |
| does the API surface reflect real lifecycle differences? | yes |
Capstone connection¶
In the capstone, this lesson matters anywhere the state model is important enough that wrong calls should be hard to make:
- approval flows
- scheduling and execution states
- activation and retirement boundaries
- partially configured versus ready objects
If the capstone API still says "everything is callable, just don’t misuse it," this page points to the next cleanup.
Exit check¶
Leave this lesson only when you can do all of these:
- explain how an API can reflect state instead of only storing it
- name one capstone transition that deserves stronger API enforcement
- explain when a runtime guard is enough and when a state-specific surface is clearer