Repository navigation
fix: convert Python untagged union members - #173
Merged
Merged
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
adamcavendish
force-pushed
the
adamcavendish/python-union-conversion
branch
from
November 11, 2026 04:49
2fe3605 to
35b9cdc
Compare
- Share model emission and enum-aware union conversion across httpx and requests so typed members serialize to JSON and inbound values become dataclasses. - Expose firstMatch, strict, and raw policies while retaining concrete-member priority, original delegate boundaries, finite null facts, and recursive guards. - Match outbound tagged members against their public payload representation, count original matches before conversion, and load model dependencies lazily. - Apply the same conversion to nested containers, aliases, JSON and multipart requests, response metadata, tagged payloads, and cached lazy error bodies. - Preserve public model and API names, keep raw subtrees dynamically typed, and send required nullable union bodies as JSON null rather than omitting them. - Share multipart/error emission and recursive annotation planning across both transports without changing the output of unmigrated generators. - Retain exact render and golden contracts plus native transport and declaration consumers, including acyclic imports and typed tagged-member round trips. - Make each backend's golden-build entrypoint own golden, declaration and native contracts with one active-interpreter environment and a 3.12 static target.
adamcavendish
force-pushed
the
adamcavendish/python-union-conversion
branch
from
November 11, 2026 06:32
35b9cdc to
d3cb7fd
Compare
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.
Summary
Convert Python untagged-union members consistently in both httpx and requests
clients, preserving their existing dataclass and API names.
Problem
The generated union was only a type alias. Its containing models and HTTP methods
treated members as identity values: typed requests failed with
Object of type ClientTool is not JSON serializable, while decoded responses retained dictionariesinstead of the declared dataclasses. Finite enum constraints also need to select
the actual member rather than a different object with the same required keys.
Behavior
firstMatchstrictrawfirstMatchis the default. Concrete candidates precede opaque fallbacks. Matchingretains finite values, Python boolean/number distinctions, nullable boundaries,
and productive recursion. Delegation occurs after selection, so nested strict
errors are not swallowed by an outer alternative or nullable wrapper.
The shared Python path covers model fields, aliases, nested arrays/maps, JSON and
multipart payloads, success responses, tagged payload delegates, and lazy cached
error bodies. Required union bodies containing
Noneare sent as JSONnull.Both transports have native consumers and strict public-declaration contracts.
Compatibility
Existing constructors, method names, and public union aliases remain available.
Named union modules add
*_from_dict/*_to_dicthelpers without adding internalhelpers to package barrels.
rawdeliberately changes a union subtree's publictype to
object; callers supply JSON-compatible values themselves. Optionalrequest bodies keep the existing convention that
Nonemeans omit.This PR is Python-only. Other languages' emitters and output remain unchanged.
Dictionary/additional-property preservation and multi-member
allOfmodelingremain separate repairs; these matching policies are not full schema validation.