Repository navigation
馃挜 Make generated enums and tagged unions open - #24
Conversation
There was a problem hiding this comment.
Copilot review overview
馃煛 Changes recommended
The AST postprocessor mixes UTF-8 byte offsets with character offsets and can corrupt generated source containing non-ASCII metadata.
Review effort: Balanced
Findings: 1
What changed in this PR
This breaking change makes generated enums and tagged unions forward-compatible while flattening field-level root models.
Changes:
- Generates open string literals instead of
StrEnumclasses. - Adds dictionary fallbacks for unknown tagged-union variants.
- Collapses root-model fields and updates tests accordingly.
| File | Description |
|---|---|
scripts/鈥媋pigen/鈥媉_main__.py |
Enables literal enums and root-model collapsing. |
scripts/鈥媋pigen/鈥媝ostprocess.py |
Opens literals and tagged unions. |
baseten/鈥媍lient/鈥媘anagementapi/鈥媉models.py |
Regenerates management models. |
baseten/鈥媍lient/鈥媘anagementapi/鈥媉_init__.py |
Removes obsolete model exports. |
baseten/鈥媍lient/鈥媘odelconfig/鈥媉models.py |
Regenerates configuration models. |
baseten/鈥媍lient/鈥媘odelconfig/鈥媉_init__.py |
Updates configuration exports. |
baseten/鈥媍lient/鈥媔nferenceapi/鈥媉models.py |
Regenerates inference models. |
baseten/鈥媍lient/鈥媔nferenceapi/鈥媉_init__.py |
Removes enum exports. |
baseten/鈥媍lient/鈥媠andboxapi/鈥媉models.py |
Regenerates sandbox models. |
baseten/鈥媍lient/鈥媠andboxapi/鈥媉_init__.py |
Removes enum exports. |
tests/鈥媍lient/鈥媡est_management.py |
Tests open enums and unions. |
tests/鈥媍lient/鈥媡est_modelconfig.py |
Tests flattened root-model fields. |
tests/鈥媡est_e2e.py |
Uses the new string enum API. |
馃挕 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| line_starts[node.lineno - 1] + node.col_offset, | ||
| line_starts[node.end_lineno - 1] + node.end_col_offset, |
| INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR" | ||
|
|
||
|
|
||
| class AsyncRequestError(BaseModel): |
There was a problem hiding this comment.
I've been wondering if it would be better to create a custom OpenStrEnum class that handles unknown values well, but would allow using it's members for a call sites instead of now having str literals everywhere.
But it turns out in terms of assert_never(status)-exhaustive handling - forcing to add a branch of the unknown values that are the plain str case, your Literal approach is better.
But there is a way to combine them, by still defining constants that match the literals, e.g.
Status = Literal["ACTIVE", "PAUSED"] | str
class Statuses:
ACTIVE: Final = "ACTIVE"
PAUSED: Final = "PAUSED"
and then you can reference at call sites Statuses.ACTIVE instead of literals. The issue with the str base case is that it would not check typos at call sites, you could write "ACTVIE" without noticing.
There was a problem hiding this comment.
Makes sense, just not sure it's worth doubling the generated surface area for enumerates that aren't even used in our code. But we can add later if needed.
We have this same problem in JS and Go SDK, such is the nature of allowing any string. Same for Stainless-generated SDKs (like OpenAI, Anthropic, etc).
Another option is that we could try to limit this fix only to enumerates that are returned and leave input types closed, but we can't guarantee they will stay as only returned and it seemed like overkill. We will have this same pattern in the high-level SDK wrt enumerates, so this is also a concern there.
|
The known-tag + malformed-payload -> silent
Won't block if Go/JS parity wins, but then note it as a conscious tradeoff in the PR. btw, one cheap guard for |
This is being addressed server-side by ensuring our REST API no longer has
Agreed, will make generation fail unless every |

馃殌 What
Literal[...] | strinstead ofStrEnumclasses, so values the server adds later are accepted instead of failing validation. Enum classes such asVolumeTokenScopeare removed; pass the string ("PULL").rootdictfor a variant the server adds later (e.g. a new audit-log event type) instead of failing the whole response馃挜 This is a BACKWARDS INCOMPATIBLE change
馃捇 How
--enum-field-as-literal alland--collapse-root-modelsfor datamodel-codegen, which has no open-enum option| strto everyLiteral, except the discriminator fields that tagged unions need closedAnnotated[<union> | dict[str, Any], Field(union_mode="left_to_right")]. A known tag with a malformed payload also falls back to thedict(Go and JS don't detect that either)馃敩 Testing
.rootand enum classesty, and unit tests pass