Build1 publisher2 min readPublished
Michael J. Sullivan takes PEP 827's runtime storage problem to the Python Language Summit
PEP 827 would add conditional, comprehension and member types so Python annotations can infer return types the way Prisma's TypeScript ORM does. Michael J. Sullivan spent his Language Summit slot on how those annotations get stored for runtime users like Pydantic and FastAPI.
The Engineer · Build desk

What happened
- The PEP's CRUD example replaces separate HeroPublic, HeroCreate and HeroUpdate classes with aliases such as type HeroUpdate = Update[Hero] over a single Hero model.
- Sullivan said the PEP was inspired by TypeScript but, importantly, is not modeled after TypeScript.
- PEP 827 was designed so that adopting it requires no new Python keywords.
- The PEP also proposes new operators, tuple slicing and length, iteration over unions and attribute type lookup, with a mypy-based prototype for every feature.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- capability An ORM could ship Public, Create and Update operators once, so an application declares one model per table and stops hand-syncing a class for each CRUD operation.
- constraint Because Python evaluates annotations itself at runtime, a computed alias has to produce real members when Pydantic or FastAPI inspects it, so the storage design decides what those libraries see.
- decision With only a mypy-based prototype, other type checkers would each have to implement conditional, comprehension and member evaluation before library authors can depend on these types.
In the Prisma query, the argument object selects `name`, `email` and `posts`. The inferred result type contains exactly those fields, with `posts` expanded into records carrying `id`, `title`, `content` and `authorId` [2]. The type follows the values passed in [2]. PEP 827 aims for the Python version of that, with return types inferred from a function's input parameter types [3].
The core is three primitives. A conditional type is written `true_type if bool_type else false_type`. A comprehension type is written `*[t for t in Iter[iter_t]]` and can take `if` clauses. `typing.Members[t]` returns an iterable of a type's members, each exposing `.name` and `.type` [7]. I'd expect `Update` to be built as a comprehension over `Members[Hero]` that makes each member optional, because the report defines the Update model as one where every property is optional, to support PATCH [4].
The CRUD case is where the saving shows. Today the example needs `HeroBase`, `Hero`, `HeroPublic`, `HeroCreate` and `HeroUpdate`, with `HeroUpdate` restating `name`, `age` and `secret_name` as optional fields defaulting to `None` [5]. The PEP 827 version is one `Hero` class, with `secret_name` marked `Field(hidden=True)`, plus three one-line aliases [6]. Five class definitions become one class and three aliases [1]. Anyone who has added a column and forgotten `HeroUpdate` has met the problem. The report says keeping the hand-written set current "requires lots of diligence and can't usually be done programmatically" [5].
Runtime storage is the part Sullivan came to discuss [1]. Pydantic and FastAPI read annotations at runtime to drive their behavior [11]. Python evaluates the types itself at runtime [13]. A computed alias therefore has to yield real members when one of those libraries inspects it. A type checker's answer does not reach them. The syntax is ordinary Python, and `if`, `for` and attribute access already have runtime meanings. Sullivan said "This was complicated by our desire to use Python-y syntax," naming `if`, `for` and dot notation [12].
I think the Python-syntax choice is the right one for the people who read and write these types, and the cost lands on the runtime. Sullivan said Python and JavaScript are "very different languages," so the system ended up looking "quite a bit different" from TypeScript [14].
The PEP includes a mypy-based prototype for every proposed feature [10]. That shows one static checker can compute these types. For the prototype to say anything about Pydantic or FastAPI, runtime evaluation would have to produce the same members mypy computes. The available text of the summit report stops before it describes the storage design Sullivan proposed.
What to watch
- The storage design Sullivan proposed for runtime evaluation of computed aliases such as Update[Hero], and whether Pydantic and FastAPI need a new API to read them.
- Whether type checkers other than mypy implement conditional, comprehension and member types from the PEP's prototype.
- Whether SQLModel or other ORMs publish Public, Create and Update operators built on the PEP 827 primitives.