Repository navigation
refactor(codegen): expand Python flattened fields from the shared layout - #211
Merged
Merged
Conversation
Python's flattened-field expansion was the last flatten walk with its own traversal of the raw schema, its own Option unwrapping and its own depth limit. It now reads its structure from codegen/schema/layout.rs, as OpenAPI and Python's optional-group validator already do since #204. Layout records what Python needs that it used to drop: the definition of a flattened enum, and why a type's keys are unknown (an untagged or externally tagged enum, a primitive, an unresolved name, too deep, or unsupported). OpenAPI only reads keys() and has_required_key(), so its output is unchanged. The four call sites now pass the flattened field itself, so group optionality comes from the shared presence rule instead of each caller. Generated output is unchanged except in two cases: - A flattened #[serde(transparent)] struct with a named field contributes the keys of the struct it wraps, as serde writes them. Python used to render the wrapper's own field, so the model rejected serde's output. Derived schemas keep such wrappers unless fold_transparent_types() is called. - Flattening a tuple struct is a codegen error. It used to generate a field named `0`, which isn't valid Python. Tests pin the depth limit, a flattened unit type and the errors for a flattened primitive or unresolved type. The codegen coverage wire fixture flattens a transparent struct, so test_wire.py replays serde's bytes through the generated client; it fails on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjkNsfHSd5osRevK95McpQ
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
📖 Documentation Preview: https://reflectapi-docs-preview-pr-211.partly.workers.dev Updated automatically from commit 64d2820 |
antonzherdev
approved these changes
Oct 29, 2026
This was referenced Oct 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows #204, another step towards #96 and #129. #204 moved OpenAPI and Python's optional-group validator onto a shared flattened layout, and left one walk for later:
This PR moves that walk onto the layout. It was the last flatten walk with its own pass over the raw schema, its own
Optionunwrapping and its own depth limit.The layout
codegen/schema/layout.rsnow keeps two things Python needs and used to drop:InternallyTaggedandAdjacentlyTaggedcarryenm.Layout::Unknown(Opaque)says which:Enum: an externally tagged or untagged enumPrimitive:(), which has no keys, or a type such asu32, which can't be flattenedUnresolved: the name isn't in the typespaceTooDeep: past the depth limitUnsupported: a tuple struct, a transparent struct without exactly one field, or anOptionwithout an argumentOpenAPI only calls
keys()andhas_required_key(), so its output is unchanged.Python
collect_flattened_fieldstakes the flattened field, builds itsFlattenedGroup, and expands it with one exhaustivematchover the layout.flattened_group_required, depth0, field name) now comes from the group.make_flattened_fieldandcollect_flattened_enum_fieldsare unchanged.Output
Every generated file is byte-identical to main, except in two cases.
A flattened
#[serde(transparent)]struct with a named field now contributes the keys of the struct it wraps, as serde writes them:#204 said derived schemas weren't affected by transparent wrappers. That's true for a tuple wrapper like
struct W(Inner), which reflection replaces with the wrapped type. A wrapper with a named field keeps its own definition unless the builder callsfold_transparent_types(). OpenAPI has followed such wrappers since #204, and Python now does too.Flattening a tuple struct is a codegen error. Main generated a field named
0, which isn't valid Python, soruff formatfailed on it. Serde flattens a newtype struct transparently, but the layout can't describe one yet, and following it would change OpenAPI output. That belongs in its own PR.Both are in the CHANGELOG under Unreleased.
Testing
context: TraceContext→trace_id: strchange above.test_wire.pyreplays serde's own bytes through the generated client. It fails 12/12 on main and passes 12/12 here.(), and the errors for a flattened primitive and an unresolved type. They pass unchanged.Opaquereason, tagged enums keeping their definition, transparent structs.fold_transparent_types(), so it would pass on main too.cargo fmt --check, clippy-D warnings --all-targets, andcargo test --workspace --all-features: 364 passed, main's 355 plus 9 newNot changed
These Python paths still read the raw schema for flatten and are next:
materialize_nested_policy_flattenrender_struct_with_flattenvariant_flattened_groupsFlattened fields still lose their field descriptions, because the template drops any description starting with
(flattened. That predates this change.Generated by Claude Code