ADR 0007: Handwritten schemas and type stubs¶
Status: accepted. Supersedes ADR 0006.
Decision¶
Generate only adjacent .pyi stubs with pysely typgen.
Do not generate schema-specific runtime implementations.
SchemaDefinition.connect() binds the handwritten schema to a dialect.
Shared SchemaClient, FlatQuery, and QueryCore code handles execution.
Generated client and query names describe those runtime objects.
They exist only in stubs; annotation imports require TYPE_CHECKING.
Type representation¶
- Predicates and callbacks share overloads by schema value type.
- Generic column unions track which columns are available.
selectpreserves the selected key and value type.select_asgroups columns by value type and tracks the alias.- A flat
TypeVarTuplestores result fields; the row stub supports 64 lookup positions.
Why a separate scope base?¶
Putting scope checks and variadic result fields in one explicit receiver caused incorrect mypy nullability inference.
The non-variadic _QueryScope base checks table membership.
The query's field pack retains the selected result types.
Both checkers use the same declarations. No checker-specific branches or plugins are required.
Remaining limits¶
- Exact
selectoverloads remain the large-schema bottleneck. - Enum completion may suggest unrelated values; invalid arguments still fail.
- Right/full joins use conservative nullability.
- Lists and dynamic aliases retain their documented typing limits.
See Schema and typing for user-facing details.
Removed approaches¶
The fixed-scope TOML prototype and generated-runtime path were removed. They are not compatibility modes.
Stubs use deterministic compact formatting. Tests check their public signatures directly.
Generator optimization follow-up¶
Already-nullable columns use one projection overload, preserving the existing join state. Required columns retain separate normal and outer-join forms.
The renderer emits final stub signatures directly. It no longer builds runtime wrappers or nested field types just to transform and discard them.
Cross-table signature merging failed scope or inference checks in the tested prototypes. State aliases reduced bytes but slowed joined completions; neither was kept.