Skip to content

[Python] Consume TCGC LRO status metadata and operation ID - #12565

Draft
iscai-msft wants to merge 1 commit into
microsoft:mainfrom
iscai-msft:python-tcgc-lro-metadata
Draft

iscai-msft wants to merge 1 commit into
microsoft:mainfrom
iscai-msft:python-tcgc-lro-metadata

Conversation

@iscai-msft

@iscai-msft iscai-msft commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Summary

Consume @azure-tools/typespec-client-generator-core 0.74.0 LRO status metadata, JSON propertySegments, and ordered operation-ID sources. Azure operations annotated with @lroStatusMetadata or @lroOperationId now return generated MetadataLROPoller / AsyncMetadataLROPoller; unannotated operations retain their existing public poller types.

  • details exposes selected values by Python client name using existing generated deserializers. Snapshots replace missing/changing values, include initial monitor and failed/canceled responses, and survive a final-resource GET.
  • operation_id exposes a selected body ID with polling-URI fallback, also available in details. URI extraction uses the modeled path parameter and percent-decodes the ID, without changing the complete polling URL or query parameters.
  • Continuation rehydration preserves Azure Core's token format and URI fallback; selected metadata repopulates on the next monitor response. Data-plane and ARM polling semantics are preserved.
  • Enable Spector azure/client-generator-core/lro/metadata and azure/client-generator-core/lro/operation-id; add emitter/lifecycle regressions, documentation, and a feature changeset.

Contract sources reviewed: status metadata, property segments, operation identity, and their TCGC interfaces/decorator/guideline contracts.

poller = client.begin_analyze(document)
result = poller.result()
print(poller.operation_id)
print(poller.details.get("percent_complete"))

This is generated access to the selected functionality, not a drop-in replacement for every handwritten model/poller name. Structural operation status remains available through the existing status() API; @lroStatusMetadata selects auxiliary monitor properties, not structural status/error/result roles. Explicitly supplied custom polling strategies retain responsibility for their own behavior. No SDK customizations are removed.

Accepted Python LRO findings

Traversed all 97 accepted Python LRO / polling findings from the customization database exported by iscai-msft/typespec-azure's sdk-customization-metrics branch (accepted_customizations, i.e. counted = 1, filtered to Python). The full classification identifies 10 covered metadata/identity facets across 4 SDK packages and 87 not covered. Coverage refers to individual facets, not necessarily the complete surrounding customization.

Python LRO customization findings

Covered refers only to the ID or auxiliary metadata facet after emitter support ships. Custom terminal states, result projection, and paged LRO results remain not covered. Related findings are grouped; each 12-character identifier is a distinct finding.

SDK package handwritten code (commit-pinned GitHub link with line range) what generated code now provides TypeSpec annotation the spec needs (@lroStatusMetadata / @lroOperationId)
azure-ai-contentunderstanding Binary analyze wrappers with an octet-stream default and custom poller projection 85c195a61f49: L292-L303 L332-L347 L255-L266 L295-L310
Code-point analyze wrappers with sentinel-aware delegation and poller adaptation a8fb24f5b77b: L216-L228 L260-L290 L179-L191 L223-L253
Not covered: Input defaults, delegation and return-wrapper adaptation are not metadata exposure. Not applicable.
azure-ai-contentunderstanding Set a default polling interval in sync and async client constructors cf47368e050f: L93-L101 L56-L64 Not covered: Polling-interval defaults are unrelated to metadata and operation-ID selection. Not applicable.
azure-ai-discovery Asynchronous operation resource-status selection 1040bfcd7635: L37-L45 L80-L106
Resource provisioning-state status extraction 1198ea0cb786: L44-L52 L99-L122
Not covered: Choosing a structural polling status changes polling behavior, which these decorators do not control. Not applicable.
azure-ai-discovery Immediate completion without an operation-location header 711311865f5a: L68-L89 L99-L117
Asynchronous immediate-completion polling fallback 8183e31b5cff: L58-L77 L83-L101
Not covered: Immediate completion when the location header is absent is a custom polling rule. Not applicable.
azure-ai-documentintelligence Rewritten begin_* LRO operations 156ad504890e: L71-L252 L65-L235 Not covered: The rewritten operations construct pollers and deserialize operation results; metadata annotations alone do not replace that behavior. Not applicable.
azure-ai-documentintelligence Default polling interval of 1s 2b94565e13fb: L18-L48 L51-L81 Not covered: Polling-interval defaults are unrelated to metadata and operation-ID selection. Not applicable.
azure-ai-documentintelligence Analyze document overloads returning custom poller 6af168036359: L386-L509 L366-L485 Not covered: Request-body overloads and exact custom poller return types are not generated by these annotations; ID exposure is covered separately. Not applicable.
azure-ai-documentintelligence Result unwrapping and final-state-via 7df5e8bab0d0: L254-L383 L237-L364 Not covered: Nested result projection and final-result behavior are outside the two metadata features. Not applicable.
azure-ai-documentintelligence Custom LROPoller subclass 84ef9b82d1f9: L39-L68 L38-L63 L15-L15 L84-L88 Covered: The operation ID can be exposed from the linked monitor URI; compatibility of the custom poller class and continuation token is not implied. @lroOperationId on the linked monitor operation's ID path parameter.
azure-ai-language-conversations Continuation factory reconstructs the custom async poller type 09c11e08712d: L114-L124
Continuation factory reconstructs the custom synchronous poller 744566b4b930: L119-L129
Not covered: Reconstructing a particular custom poller class from a continuation token is not guaranteed by metadata annotations. Not applicable.
azure-ai-language-conversations Wrap generated job submission with custom polling and result shaping 5d6066d29d8d: L207-L215 L225-L238 L264-L307
Wrap async job submission with custom polling and result shaping 78bdbef476e5: L202-L210 L220-L233 L260-L312
Not covered: The LRO returns paged results and performs custom result shaping; metadata exposure alone does not provide paging. Not applicable.
azure-ai-language-conversations Expose operation ID and available async operation-state metadata a5116d4edea0: L39-L53 L59-L112
Expose operation ID and available operation-state metadata dd55d7d85ef9: L43-L57 L63-L117
Covered: The ID and auxiliary job metadata can be exposed on the poller. Status and error retain their normal structural roles; paged results are not covered. @lroOperationId on the linked monitor ID path parameter; @lroStatusMetadata on auxiliary monitor fields such as timestamps, display name, and statistics.
azure-ai-language-conversations-authoring Case-insensitive job-state normalization 0dca75e5bfde: L83-L92 Not covered: Custom terminal-state and cancellation-spelling normalization affects polling behavior. Not applicable.
azure-ai-language-conversations-authoring Versioned synchronous poller continuation token 17a83c57e4e4: L200-L248
Versioned asynchronous poller continuation token 6ce12df4e32d: L366-L414
Not covered: Custom continuation-token serialization, decoding, or rehydration is not supplied. Not applicable.
azure-ai-language-conversations-authoring Job URL used for polling and final retrieval 1a6f2f16771e: L59-L71 L94-L96 Not covered: Choosing the polling and final-GET URL is protocol behavior, not an exposed operation ID. Not applicable.
azure-ai-language-conversations-authoring Awaited job polling and terminal final GET 80637aaa6d98: L251-L270 L298-L306 L321-L325
Interval polling until terminal state followed by final GET f1f898024b9e: L100-L113 L143-L158
Not covered: The custom polling loop, wait interval, terminal states, and final GET are not changed. Not applicable.
azure-ai-language-conversations-authoring Not-found exception treated as in-progress during polling 8e85c51c2543: L166-L182
Async not-found exception treated as in-progress f14d9fbaa9b6: L332-L347
Not covered: Treating not-found responses specially and controlling retries are custom polling behaviors. Not applicable.
azure-ai-language-conversations-authoring Transport-aware asynchronous polling delay 948db1d638f1: L308-L319 Not covered: Transport-aware polling delays are not provided by metadata annotations. Not applicable.
azure-ai-language-conversations-authoring Required Operation-Location and formatted polling URL bff73db6dc3b: L115-L141
Async job polling initialization from Operation-Location c81f971a3fda: L272-L296
Not covered: Requiring and formatting the polling URL controls poll initialization; this finding does not expose an operation ID. Not applicable.
azure-ai-language-conversations-authoring Synchronous modern/legacy polling GET adapter cd30f7db5c3e: L185-L197
Asynchronous modern/legacy polling GET adapter d9ebe376083a: L350-L363
Not covered: Modern/legacy transport adapters are independent of metadata exposure. Not applicable.
azure-ai-language-conversations-authoring Successful initial HTTP codes still mean in progress db75e889578f: L74-L80 Not covered: Treating successful initial HTTP responses as in-progress is a custom completion rule. Not applicable.
azure-ai-language-documents Recreate the custom async poller from a polling-method token 1419ca16d5d3: L86-L96
Reconstruct the custom poller class from a continuation token 2b221bb30880: L86-L96
Not covered: Reconstructing a particular custom poller class from a continuation token is not guaranteed by metadata annotations. Not applicable.
azure-ai-language-documents Job-submission poller returns paged task containers 1821924e4d94: L118-L129 L154-L245
Async submission poller produces async pages of task containers 2c7cd7789d86: L118-L129 L155-L246
Not covered: The LRO returns paged results and performs custom result shaping; metadata exposure alone does not provide paging. Not applicable.
azure-ai-language-documents Cancellation LRO selects polling behavior and a completion-only result 25963a768b3c: L247-L257 L273-L319
Async cancellation wrapper returns a completion-only poller 26e384a15db6: L248-L258 L274-L320
Not covered: Cancellation-specific poller selection and no-result callbacks are independent of metadata exposure. Not applicable.
azure-ai-language-documents Expose an operation ID and cached job-state metadata 2e3a89bc4b0f: L33-L84 L322-L325
Async poller exposes an operation ID and cached job metadata 540222772ea6: L33-L84 L323-L326
Covered: The ID and auxiliary job metadata can be exposed on the poller. Status and error retain their normal structural roles; paged results are not covered. @lroOperationId on the linked monitor ID path parameter; @lroStatusMetadata on auxiliary monitor fields such as timestamps, display name, and statistics.
azure-ai-ml Handwritten model-version PUT with metadata insertion and LRO result 95e224281919: L22-L50 L53-L111 L124-L128 Not covered: Request serialization and insertion of model system metadata are unrelated to LRO status metadata. Not applicable.
azure-ai-translation-document operation-id-details-and-continuation-poller-facade 2ca2279258dc: L83-L126 Covered: The ID and auxiliary translation-status metadata can be exposed on the poller. Exact TranslationStatus wrapper shape, continuation compatibility, and paged results are not covered. @lroOperationId on the linked monitor ID path parameter and/or its string-like ID property; @lroStatusMetadata on auxiliary monitor properties.
azure-ai-translation-document body-status-location-fallback-and-validation-error-adapter a67a54622f1e: L218-L283 Not covered: Polling-location fallback and service-specific validation errors require custom protocol behavior. Not applicable.
azure-ai-translation-document bidirectional-cancellation-status-spelling-helper ade1030ac156: L69-L80 Not covered: Custom terminal-state and cancellation-spelling normalization affects polling behavior. Not applicable.
azure-ai-translation-document patched-start-operation-result-callback-and-poller-selection bbb11757294c: L286-L347 Not covered: The operation's result callback, return conversion, and poller selection are not provided by the annotations. Not applicable.
azure-ai-translation-document translation-body-state-continuation-and-terminal-loop de2752a3d6b3: L65-L66 L129-L215 Not covered: Although an operation ID can be exposed, the custom terminal states, polling loop, and continuation behavior remain unsupported. Not applicable.
azure-batch Job deletion poller around an initial protocol response 3da23e58c9e3: L60-L74 L119-L145
Asynchronous job deletion poller wrapper 423364ad1431: L61-L75 L120-L143
Job schedule deletion poller wrapper 4539ea409fed: L308-L321 L361-L382
Asynchronous job enabling poller wrapper 5e76a5e9f514: L229-L242 L283-L304
Asynchronous job schedule deletion poller wrapper 92395b7834d4: L306-L319 L359-L380
Asynchronous job disabling poller wrapper d01f51d6d9f4: L145-L159 L205-L227
Pool deletion poller wrapper e32bd36977bf: L384-L397 L445-L466
Job enabling poller wrapper eb3be364976d: L231-L244 L285-L306
Job disabling poller wrapper fc21c92376c6: L147-L161 L207-L229
Asynchronous pool deletion poller wrapper fff2572d9529: L382-L395 L443-L464
Not covered: These batch wrappers construct resource-specific polling methods and no-result operations, rather than exposing selected metadata. Not applicable.
azure-confidentialledger Ready-state poller around ledger-entry reads 2f678c44a646: L122-L125 L144-L160 L76-L79 L98-L114
Ready-state poller around receipt reads 9e9832db2d45: L162-L188 L116-L142
Not covered: Polling a resource until its custom Ready state is protocol behavior. Not applicable.
azure-confidentialledger Desired-state polling lifecycle and result projection 3dcd767eab1c: L37-L82 Not covered: Custom desired-state completion and result projection are not supported. Not applicable.
azure-confidentialledger Write-then-commit orchestration retaining the write result 69e42c1fb295: L190-L196 L214-L250 L144-L146 L163-L199 Not covered: Write-then-commit orchestration and preservation of the write result are outside the metadata features. Not applicable.
azure-confidentialledger Committed-state polling with initial not-found tolerance d3fe2901ce90: L252-L256 L267-L298 L201-L203 L214-L248 Not covered: Committed-state polling, not-found tolerance, and retained-result selection are custom behavior. Not applicable.
azure-confidentialledger Sync/async state polling with bounded not-found tolerance d85d61a69907: L68-L71 L85-L119 L39-L73 Not covered: Treating not-found responses specially and controlling retries are custom polling behaviors. Not applicable.
azure-developer-loadtesting async-test-profile-run-operation-with-resource-status-polling 0aab9e4505ce: L239-L242 L464-L467 L482-L499 L502-L503
async-test-run-operation-with-resource-status-polling 1e6e6a609a61: L239-L242 L343-L351 L372-L389 L502-L503
test-profile-run-operation-with-resource-status-polling 2ea1f4bdb9c9: L258-L261 L487-L493 L508-L526 L529-L533
upload-operation-with-file-validation-polling 65ab502f7be0: L124-L126 L201-L210 L235-L255 L529-L533
test-run-operation-with-resource-status-polling 6d89a5a0e134: L258-L261 L362-L370 L392-L407 L529-L533
async-upload-operation-with-file-validation-polling f22af82c3455: L115-L118 L188-L197 L221-L236 L502-L503
Not covered: These wrappers run resource-specific pollers with service-specific completion rules. Not applicable.
azure-developer-loadtesting asynchronous-command-driven-polling-base 1ab45fe21c18: L28-L68
synchronous-command-driven-polling-base f6b0dfa86e69: L31-L71
Not covered: Command-driven polling loops and lifecycle behavior are not metadata exposure. Not applicable.
azure-developer-loadtesting async-test-run-terminal-status-strategy 22a30ac4475c: L89-L99
file-validation-terminal-status-strategy 407174c9eff6: L74-L91
async-test-profile-run-terminal-status-strategy 57d1ac8427cc: L102-L112
test-run-terminal-status-strategy 70e5924abc2e: L94-L106
test-profile-run-terminal-status-strategy 9a6a698acfb9: L109-L121
async-file-validation-terminal-status-strategy e97cf9b6250a: L71-L86
Not covered: The nonstandard terminal states control polling and cannot be supplied by @lroStatusMetadata. Not applicable.
azure-healthinsights-radiologyinsights Synchronous LRO wrapper deserializes the nested inference result 51ffd022543d: L147-L155 L171-L232 L265-L267
Asynchronous LRO wrapper extracts the nested inference result b2da8255a4ac: L153-L161 L179-L241 L276-L278
Not covered: Nested result projection and final-result behavior are outside the two metadata features. Not applicable.
azure-keyvault-administration Serialize selected response state into a versioned base64 JSON token 1fb1002b3cd6: L42-L75
Translate an encoded status URL into a refreshed continuation token 75443d5f216a: L23-L26 L94-L107
Not covered: Custom continuation-token serialization, decoding, or rehydration is not supplied. Not applicable.
azure-keyvault-administration Select full or single-key restore and shape the poller result 5f65c0f941cb: L248-L287
Adapt backup inputs, continuation and public result with custom polling wiring ddf105537bca: L159-L183
Prepare pre-backup parameters and a no-result custom poller f998a5c21629: L333-L353
Prepare pre-restore parameters and a no-result custom poller fb8cc27b8dd1: L400-L424
Not covered: Backup/restore argument adaptation, polling selection, and result conversion are not provided. Not applicable.
azure-keyvault-certificates Assemble recovery polling with an unfinished initial state 5b914706d94b: L336-L355
Validate a policy and assemble a certificate-creation poller 83357c465296: L103-L152
Seed delete polling from recovery-ID availability 89159682596d: L239-L258
Not covered: The custom readiness checks, initial-result retention, error rules, and poller construction are not covered. Not applicable.
azure-keyvault-secrets Recovery poller initialized unfinished with a live-secret GET command 0c5953162298: L441-L442 L471-L490
Async existence polling with 404-pending and 403-complete rules 156bb645951b: L13-L13 L34-L80
Delete poller initialized from recovery-ID availability and a resource GET f7f2762ba193: L316-L317 L344-L364
Not covered: The custom readiness checks, initial-result retention, error rules, and poller construction are not covered. Not applicable.
azure-keyvault-securitydomain Asynchronous download activation polling selection 0691dc1c140a: L109-L118 L138-L151
Upload activation polling selection 2f6cde0e8285: L229-L238 L254-L265
Asynchronous upload activation polling selection 57906038d977: L186-L195 L211-L222
Download activation polling selection 5d27ea2d49f5: L154-L163 L183-L194
Not covered: Activation polling selection and interval control are unrelated to the two annotations. Not applicable.
azure-mgmt-cognitiveservices Asynchronous compute-list provisioning poller 49a9860f6e67: L34-L98 L163-L196 L207-L228
Synchronous compute-list provisioning poller 6d93ab430012: L82-L146 L211-L244 L255-L276
Not covered: Polling by enumerating compute resources, with a grace period and service-specific failures, is custom behavior. Not applicable.
azure-mgmt-cognitiveservices Resource-scoped continuation token codec and rehydration c8f62b7fc161: L31-L47 L148-L154 L245-L246 L264-L270 L100-L106 L197-L198 L216-L222 Not covered: Custom continuation-token serialization, decoding, or rehydration is not supplied. Not applicable.

Validation and remaining work

Draft: published Spector fixtures are not green yet.

  • Package build, package format, full package lint, repository pnpm format, and complete emitter Vitest suite pass.
  • 28 focused lifecycle tests pass on Azure Core 1.37.0, covering data-plane/ARM, sync/async, missing/changing metadata, initial monitors, terminal failures/cancellation, full polling URLs, final-resource preservation and continuation rehydration.
  • 8 existing RPC/standard LRO HTTP tests pass; generated polling modules pass Pyright.
  • Available unrelated generator subset: 950 passed, 1 known-baseline test deselected. Broader collection also has stale generated enum/packaging-fixture dependencies; two XML serializer failures are outside the changed templates. The empty-model TypedDict test failure reproduces on unchanged HEAD.
  • Generator mypy (9 errors) and Pyright (5 errors) failures exactly match an isolated unchanged-HEAD baseline; no new generator typing failures.
  • New published Spector tests: 13 passed / 2 failed. The unescaped literal colon in /translations:start also matches /translations:start-with-path, returning the other scenario's polling URI. The generated path-ID assertion correctly rejects that response. Temporarily escaping both mock routes locally proves 15/15 pass; that dependency-only experiment was reverted and is not included in this PR.

Remaining work: correct and publish the shared Spector route fixtures, update the pinned specs dependency to that publication, and rerun the enabled sync/async combined-source cases without a local correction before marking ready.

Explicitly excluded: Azure/typespec-azure#5837 (unmerged LRO result defaults) and Azure/typespec-azure#5710 (endpoint/OAuth configurations). Neither is consumed here.

Python's Azure wrapper consumer-version bump is a separate coordinated PR; its workspace TCGC is already 0.74.0, so no artificial TCGC bump is required there.

Part of Azure/typespec-azure#5996

Co-authored-by: Copilot App <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 Nov 12, 2026
@pkg-pr-new

pkg-pr-new Bot commented Nov 12, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: ccd6333

@github-actions

Copy link
Copy Markdown
Contributor

Python emitter diff

Baseline gh:6108f07b2e52619b86c403e6703fe7db39bff26b vs this PR.

⚠️ emitter-diff failed (exit 1) — tool/build error, not a diff. See the run.

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

@github-actions

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

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

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

Generate MetadataLROPoller and AsyncMetadataLROPoller for Azure operations using @lroStatusMetadata or @lroOperationId. Their details and operation_id properties expose selected monitor metadata and server-issued identifiers, refresh on polling, and repopulate after resuming from a continuation token. Operations without these annotations retain their existing pollers.,> ,> python,> poller = client.begin_analyze(document),> result = poller.result(),> print(poller.operation_id),> print(poller.details),>

@azure-sdk-automation

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant