Skip to content

feat(http-client-python): support P1 inline discriminated unions - #12285

Draft
Libba Lawrence (l0lawrence) wants to merge 5 commits into
microsoft:mainfrom
l0lawrence:python-inline-discriminated-unions
Draft

Libba Lawrence (l0lawrence) wants to merge 5 commits into
microsoft:mainfrom
l0lawrence:python-inline-discriminated-unions

Conversation

@l0lawrence

Copy link
Copy Markdown
Member

Summary

Implement the Python P1 inline discriminated-union shape described in Azure/typespec-azure#5703 (section 2). This is a scoped Python implementation, not a resolution of the complete cross-language issue.

  • Support @discriminated(#{ envelope: "none" }) on unions with an explicit model constraint and nominal model variants declaring matching required literal discriminator properties.
  • Preserve named Python union aliases and declared model inheritance. Generate Annotated[Union[...], _DiscriminatedUnion(...)] metadata for union-local deserialization rather than replacing the union with its base model or modifying shared model registrations.
  • Honor custom discriminator names and JSON wire names; reuse existing literal-field serialization for inline tags.
  • Handle operation request/response boundaries, model properties, optional/container uses, recursion, and cross-namespace aliases. Missing or unknown tags raise DeserializationError rather than selecting the first variant.
  • Preserve ordinary untagged unions, direct model behavior, and existing @discriminator hierarchies. Add regression coverage, README documentation, and a feature changelog.

Compatibility and scope

Installed TCGC 0.73.0 exposes discriminatedOptions but not SdkUnionType.baseType. Read the compiler's explicit Union.baseType constraint and match SDK model ancestry against it; do not infer a common ancestor. The sample requires the compiler's experimental union-extends feature.

Initial support targets the default DPG model mode and explicit-base nominal variants. P2 object envelopes, default variants, structural variants, unions without an explicit model constraint, and variants without matching literal tags are unsupported and receive an explicit diagnostic. Existing skipped envelope/Spector scenarios remain untouched.

Validation

  • Emitter TypeScript build and Python wheel build passed using installed dependencies (tsc and python -m build --wheel --no-isolation), avoiding dependency bootstrapping/downloads.
  • Emitter suite: 40 passed (vitest run --config emitter/vitest.config.ts --testTimeout 20000).
  • Focused Python suites: 103 passed, 1 deselected, including 26 new cases covering Azure/unbranded runtimes and generated fixtures.
  • Actual emitted/generated Azure and unbranded SDK smoke checks passed for synchronous and asynchronous requests/responses using mocked pipeline responses, including exact inline JSON, variant selection, containers, direct models, and unknown tags.
  • Emitter Oxlint, changed generator-source Pylint, package formatting, repository pnpm format, and git diff --check passed.

Baseline caveats

  • Deselected test_models_mode_typeddict_does_not_write_empty_models_folder: its existing model-package scaffolding failure was reproduced with baseline CombinedType from HEAD before implementation was committed.
  • Direct Pylint of the generated runtime reports pre-existing template findings; rendering and linting the baseline template reproduced the same findings and 9.92/10 score. No new runtime lint findings were observed.
  • No full monorepo build/test or live Spector-server run was performed; generated-client smoke checks mocked pipeline responses.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:python Issue for the Python client emitter: @typespec/http-client-python label Oct 15, 2026
@pkg-pr-new

pkg-pr-new Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-python@12285

commit: 66679fe

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Python emitter diff

Baseline gh:a43d2ca6f2ddd4c1a1d05f2e63cd4c8a40a71b76 vs this PR.

Diff summary: 389 file(s), +31097 / -5885

Rendered diff: inline on the run summary, or the emitter-diff-html artifact.

Informational check (eng/emitter-diff); does not block the PR.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • ✅ @typespec/http-client-python
Show changes

@typespec/http-client-python - feature ✏️

Support inline discriminated unions with an explicit model constraint and nominal,> model variants. Keep the named Python union alias and declared model inheritance,,> and deserialize responses and nested properties using the configured inline,> discriminator. Inject absent discriminator tags when serializing nominal variants,> through the union without changing shared model instances. Distinguish same-named,> aliases from different namespaces. Missing or unknown tags raise DeserializationError. Object,> envelopes and default variants are not supported.,> ,> Handle transitive discriminator inheritance and narrowed literal discriminator,> fields in TypedDict views. Update @typespec/http-specs to 0.1.0-alpha.45 to,> cover the constrained union scenarios in synchronous and asynchronous clients.,> ,> tsp,> model PetBase {,> kind: string;,> name: string;,> },> model Cat extends PetBase {,> kind: "cat";,> meows: boolean;,> },> model Dog extends PetBase {,> kind: "dog";,> barks: boolean;,> },> @discriminated(#{ envelope: "none" }),> union Pet extends PetBase {,> cat: Cat,,> dog: Dog,,> },>

@azure-sdk-automation

azure-sdk-automation Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

@microsoft-github-policy-service microsoft-github-policy-service Bot added the stale Mark a PR that hasn't been recently updated and will be closed. label Oct 30, 2026
@microsoft-github-policy-service

Copy link
Copy Markdown
Contributor

Hi @Libba Lawrence (@l0lawrence). Your PR has had no update for 14 days and it is marked as a stale PR. If it is not updated within 14 additional days, the PR will automatically be closed. The stale label is removed automatically when you update or comment on your PR, or when a maintainer reviews it. You can also remove the label manually.

Merge main, resolve the union-extends test host conflict, and cover constrained discriminated unions from HTTP specs alpha.45.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot removed the stale Mark a PR that hasn't been recently updated and will be closed. label Nov 2, 2026
…sync

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
… typed dicts

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ntegration workflow

Consolidate the Python union changelog into one feature entry.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:python Issue for the Python client emitter: @typespec/http-client-python eng

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant