Skip to content

[AutoPR azure-communication-identity]-generated-from-SDK Generation - Python-6802367 - #48938

Draft
azure-sdk-automation[bot] wants to merge 15 commits into
mainfrom
sdkauto/azure-communication-identity-6802367
Draft

[AutoPR azure-communication-identity]-generated-from-SDK Generation - Python-6802367#48938
azure-sdk-automation[bot] wants to merge 15 commits into
mainfrom
sdkauto/azure-communication-identity-6802367

Conversation

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

Configurations: 'specification/communication/data-plane/Identity/tspconfig.yaml', API Version: 2026-09-23, SDK Release Type: stable, and CommitSHA: '1893171028aed5a757fc78c2d4aa439c14df4afc' in SpecRepo: 'https://github.com/Azure/azure-rest-api-specs' Pipeline run: https://dev.azure.com/azure-sdk/internal/_build/results?buildId=6802367 Refer to https://eng.ms/docs/products/azure-developer-experience/develop/sdk-release/sdk-release-prerequisites to prepare for SDK release. Release plan link: https://azsdk-releaseplan-dashboard-hveph5aqhhcfhtgu.westus-01.azurewebsites.net/?releaseplan=36401 Submitted by: johnfraser@microsoft.com

…onfig.yaml', API Version: 2026-09-23, SDK Release Type: stable, and CommitSHA: '1893171028aed5a757fc78c2d4aa439c14df4afc' in SpecRepo: 'https://github.com/Azure/azure-rest-api-specs' Pipeline run: https://dev.azure.com/azure-sdk/internal/_build/results?buildId=6802367 Refer to https://eng.ms/docs/products/azure-developer-experience/develop/sdk-release/sdk-release-prerequisites to prepare for SDK release.
@azure-sdk-automation azure-sdk-automation Bot added the auto-release When merged to main, release pipelines for this PR's changed packages trigger automatically. label Sep 9, 2026
Copilot AI balanced review requested due to automatic review settings September 9, 2026 02:35
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
10 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

One or more issues must be addressed before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Regenerates azure-communication-identity from the 2026-09-23 TypeSpec API and migrates package metadata to pyproject.toml.

Changes:

  • Adds generated Teams Extension models and operations.
  • Updates packaging, API metadata, tests, and samples.
  • Removes the existing handwritten public client and shared implementation.
File summaries
File Description
sdk/communication/azure-communication-identity/tsp-location.yaml Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/test_utils.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/test_user_credential.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/test_user_credential_async.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/test_token_utils.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/test_token_exchange.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/test_token_exchange_async.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/test_identifier_raw_id.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/test_entra_token_guard_policy.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/test_entra_token_guard_policy_async.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/tests/_shared/communication_service_preparer.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/sdk_packaging.toml Updated as part of this pull request.
sdk/communication/azure-communication-identity/samples/identity_samples.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/samples/identity_samples_async.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/pyproject.toml Updated as part of this pull request.
sdk/communication/azure-communication-identity/MANIFEST.in Updated as part of this pull request.
sdk/communication/azure-communication-identity/CHANGELOG.md Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/py.typed Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/aio/_communication_identity_client_async.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_version.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_utils.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils_async.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential_async.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/token_utils.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/token_exchange.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/token_exchange_async.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/policy.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/models.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/entra_token_guard_policy.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/entra_token_guard_policy_async.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_shared/auth_policy_utils.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/types.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/py.typed Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/operations/_patch.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/operations/init.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/models/_patch.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/models/_models.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/models/_enums.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/models/init.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/aio/operations/_patch.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/aio/operations/_operations.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/aio/operations/init.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/aio/_patch.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/aio/_configuration.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/aio/_client.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/aio/init.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/_version.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/_utils/init.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/_patch.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/_configuration.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/_client.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_generated/init.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_communication_identity_client.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/_api_versions.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/identity/init.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/communication/init.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/azure/init.py Updated as part of this pull request.
sdk/communication/azure-communication-identity/apiview-properties.json Updated as part of this pull request.
sdk/communication/azure-communication-identity/api.metadata.yml Updated as part of this pull request.
sdk/communication/azure-communication-identity/api.md Updated as part of this pull request.
sdk/communication/azure-communication-identity/_metadata.json Updated as part of this pull request.
Review details

Suppressed comments (1)

sdk/communication/azure-communication-identity/pyproject.toml:82

  • The PR declares a stable SDK release and VERSION is 1.6.0, so retaining is_stable = false misclassifies the package for repository packaging/release automation. Set this flag to true.
  • Files reviewed: 66/66 changed files
  • Comments generated: 5
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

"TeamsExtensionUserIdentifier",
"TeamsExtensionUserProperties",
]
__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore
return deserialized # type: ignore


class TeamsExtensionOperationsOperations: # pylint: disable=docstring-missing-param
Comment thread sdk/communication/azure-communication-identity/pyproject.toml Outdated
## 1.6.0 (2026-09-09)

### Features Added
skip changelog generation for data-plane package and please add changelog manually.
Comment on lines +1 to +2
```py
``` No newline at end of file
@JohnRFraser

Copy link
Copy Markdown
Member

⚠️ Do not merge — this PR removes hand-written code

It deletes 20 hand-written files and silently empties 2 more, including the convenience client and its async mirror, _utils.py, and the entire _shared/ tree. __init__.py survives but drops from 17 exports to 0, and _version.py loses SDK_MONIKER — neither shows as a deletion in the diff.

This is not caused by the spec change. del_outdated_generated_files() in packaging_tools/generate_utils.py computes its target as package_dir.split("-")[0], which for azure-communication-identity is azure, and removes the whole namespace tree before generation. The emitter then restores only what it owns.

generation-subdir is working correctly — 24 files land in _generated/ as intended. The deletion is a separate, pre-existing issue in shared tooling, and is being raised separately.
This pull request contains only the generated half of the change. The hand-written convenience layer that it depends on is not in it, so the failing checks are expected rather than a regression.

Context. ACS Identity is moving from AutoRest to the TypeSpec DPG emitter and adding stable api-version 2026-09-23. The spec-side configuration merged as azure-rest-api-specs#46186 (commit 18931710), which added a client.tsp carrying the client-name and access directives, plus emitter options in tspconfig.yaml. This PR is the output of the SDK Generation pipeline run against that merged spec, under release plan 36401.

Why it is red. The pipeline regenerates the generated layer against main, where the hand-written layer is still shaped for AutoRest. The generated code and the hand-written code therefore disagree, and the build fails. Regenerating cannot resolve this: the failing code is not generated, so no amount of generation reaches it.

I have moved this to draft so it is not merged in this state.

johnfraser-msft and others added 8 commits September 10, 2026 09:57
Adapt the hand-written sync and async clients to the DPG-generated service
layer while keeping the public API surface unchanged.

Generated-shape changes absorbed here:
- Client class renamed CommunicationIdentityClient -> IdentityClient.
- One operation group became three (identity_operations, teams_user_operations,
  teams_extension_operations), matching the three TypeSpec interfaces.
- Enum renamed CommunicationTokenScope -> CommunicationIdentityTokenScope;
  aliased back so the public name is unchanged.

Two behaviors deliberately preserved against generator changes:

1. AccessToken.expires_on stays the raw service string. TypeSpec declares
   expiresOn as utcDateTime, so attribute access now deserializes to datetime.
   Reading the key instead returns the untouched wire value. Note .isoformat()
   is not equivalent: it changes the format and truncates 7-digit fractional
   seconds to 6.

2. expiresInMinutes is omitted when not supplied. msrest dropped None fields
   during serialization; the generated code forwards the request body as-is,
   which would send an explicit null for a property the service constrains to
   [60, 1440].

Default API version moves 2023-10-01 -> 2025-06-30.

Verified: 97 offline unit tests pass, identical to the pre-migration baseline.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add V2026_09_23 to the ApiVersion enum and make it the default. Bump the
package to 2.0.0, a coordinated major increment across all four language
SDKs rather than a semver-driven one: the public API surface is unchanged
and the 97 offline unit tests pass exactly as before.

Re-verified after regeneration:
- expiresInMinutes is still omitted when not supplied and present when it is,
  sync and async. This is the build_token_request_body fix; msrest used to
  drop None fields, and without it an explicit null reaches a property the
  service constrains to [60, 1440].
- AccessToken.expires_on is still the raw service string, byte-identical.
- Every public attribute on every returned object reads back populated,
  sync and async, including the identifier properties and kind.
- api-version=2026-09-23 confirmed on the wire.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The AutoRest configuration that recorded this constraint was deleted with
swagger/SWAGGER.md, so to_access_token is now the only place the reasoning
survives. Record it there: that returning a datetime would break callers, that
this already happened once under AutoRest, and that .isoformat() is not an
adequate substitute because it reformats and truncates fractional seconds.

Comment only - no behavior change. 97 tests pass.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Every wire check performed during this migration was an ad hoc probe. None was
committed, so nothing in CI asserted the three behaviours the DPG move silently
changed. Grepping tests/ for api-version returned nothing.

Adds 9 tests covering, at the transport layer:
- expiresInMinutes omitted when no expiry is requested, present when one is
- AccessToken.expires_on carrying the raw service string, not a datetime
- the targeted api-version reaching the wire on all six operations

Each assertion is mutation-tested. Reverting build_token_request_body fails 2,
reverting to_access_token to attribute access fails 3, and reverting
DEFAULT_VERSION fails 2.

That last figure was 1 before this commit. Mutation testing showed the
per-operation check compared the wire against DEFAULT_VERSION itself, which is
self-referential and cannot detect a wrong default. It now asserts a literal.

106 offline tests pass (97 existing plus these 9).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The TypeSpec emitter drops three request headers the AutoRest client sent:
Content-Type on the bodyless create_user POST, and Accept on revoke_tokens
and delete_user. The service is indifferent to all three - measured against a
live resource - but a proxy, gateway or request log keying on headers would
observe the change, so under the black-box-identical requirement they are
restored.

Accept is restored by passing headers= through to the generated operation.

Content-Type could not be. The generated create operation nulls content_type
whenever no body is present, twice:

    content_type = content_type if body else None
    content_type = content_type or "application/json" if body else None

so no argument reaches the request builder. It is restored by a SansIOHTTPPolicy
matched narrowly to a bodyless POST to the identities collection, leaving the
body-bearing create_user_and_token untouched.

That same discard also drops a caller-supplied Content-Type, which the AutoRest
client honoured - a second regression found while testing the first. create_user
now moves any caller value into the request context for the policy to reapply.

Verified: all six operations compared against the pre-migration client, sync and
async, for accept and content-type - zero mismatches. create_user still sends no
body. 15 wire tests (6 new), each mutation-tested: removing the policy fails 2,
neutering the Accept merge fails 2. 112 offline tests pass.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
_shared/ (13 files) and aio/__init__.py were removed by the generation
pipeline's unscoped rmtree of the package namespace directory. They are
unmodified by this migration, so no convenience-layer commit carries them;
they are restored verbatim from the merge-base.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
client.tsp renames the token scope union for Python, so the generated enum is
CommunicationTokenScope directly and the compensating alias import now refers
to a name that no longer exists.

Hand-written change only; the generated layer is left exactly as the pipeline
emitted it.

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

Copy link
Copy Markdown
Member

Pushed the hand-written convenience layer onto this branch, so the PR now carries both halves rather than the generated layer alone.

The generated layer is untouched — all 23 files under _generated/ are byte-identical to the pipeline's own output.

This addresses the review comments above: the public API is restored (__init__.py exports 17 names again), _version.py carries SDK_MONIKER, and the _shared modules the tests and samples depend on are back.

One thing reviewers should know: part of this is a workaround, not a fix.

The generation pipeline deletes the package's entire hand-written layer before generating. del_outdated_generated_files() in packaging_tools/generate_utils.py computes its target as package_dir.split("-")[0], which for azure-communication-identity is azure — so it removes the whole namespace tree and relies on the emitter to restore what it owns. Anything the emitter does not emit is lost. That accounts for 22 files here: 20 deleted outright, and 2 more silently reset to empty stubs (__init__.py to zero exports, _version.py losing SDK_MONIKER), which do not appear as deletions in the diff.

Most of those files come back by re-applying the migration commits. 14 do not_shared/ and aio/__init__.py — because the migration never needed to modify them, so no commit carries them. They are restored here verbatim from the merge base.

That means this branch is repaired but not durable: the next pipeline run on this package will delete them again. The underlying issue is in shared tooling and affects packages well beyond this one; it is being raised separately.

Also valid from the review and worth fixing at source: pyproject.toml marks the distribution as Beta while setup.py classifies it Production/Stable. That inconsistency is in the pipeline-generated file.

The pipeline-generated pyproject.toml classifies the distribution as
"Development Status :: 4 - Beta" while the package ships as 2.0.0, a stable
GA release. The repo's own gate rejects that combination:

    ci_tools.functions.verify_package_classifiers(
        "azure-communication-identity", "2.0.0",
        ["Development Status :: 4 - Beta"])
    -> False, "has version 2.0.0 and is a GA release, but had development
       status 'Development Status :: 4 - Beta'. Expecting a development
       classifier that is equal or greater than
       'Development Status :: 5 - Production/Stable'."

setup.py does already carry "Development Status :: 5 - Production/Stable",
but that has no effect here and is not a mitigation. pyproject.toml declares a
[project] table, so under PEP 621 it is authoritative for package metadata and
setup.py's classifiers are ignored entirely. Building the sdist before this
change produced:

    Version: 2.0.0
    Classifier: Development Status :: 4 - Beta

and after it produces "Development Status :: 5 - Production/Stable". The gate
function returns True for the corrected value.

pyproject.toml is emitted by the generation pipeline, so this recurs on every
regeneration until the emitter or its configuration is corrected upstream.

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

Copy link
Copy Markdown
Contributor
[Pilot] PR Pipeline Failure Analysis

What failed

Azure Pipeline build 6811270 (python - pullrequest) failed identically across all 6 platform jobs (macos311, ubuntu2404_310, ubuntu2404_310_coverage, Ubuntu2404_313, Ubuntu2404_314, windows2022_312), for both the sdist and whl test runs of azure-communication-identity:

~50 tests fail per file in sdk/communication/azure-communication-identity/tests/test_communication_identity_client.py and test_communication_identity_client_async.py (e.g. test_create_user, test_create_user_from_token_credential, test_get_token*, test_revoke_tokens*, test_delete_user*). Every failure has one of two forms of the same root cause: this PR bumps the generated client's API version to 2026-09-23, but the checked-in test recordings were captured against api-version=2023-10-01. The test-proxy playback engine can't match the new request URI to any recorded entry, and the identical mismatch pattern repeats verbatim across every platform/job — a single shared-fixture/root cause, not per-platform issues.

Relevant pipeline output
azure.core.exceptions.ResourceNotFoundError: Playback failure -- for help resolving, see https://aka.ms/azsdk/python/test-proxy/troubleshoot. Error details:
Unable to find a record for the request POST (sanitized.communication.azure.com/redacted)
Uri doesn't match:
    request (sanitized.communication.azure.com/redacted)
    record  (sanitized.communication.azure.com/redacted)

--- separate assertion-style failure (same root cause) ---
tests/test_communication_identity_client.py:95: in test_create_user_and_token_with_invalid_custom_expirations
>       assert str(ex.value.status_code) == "400"
E       AssertionError: assert '404' == '400'
E         - 400
E         + 404

(The service call intended to return 400 Bad Request for invalid input instead returns 404 Not Found from the test-proxy, because the mismatched-version recording produces a "record not found" 404 rather than the expected service error.)

Recommended next steps

  • Re-record the azure-communication-identity test cassettes against the new 2026-09-23 API version (or update recordings to match this PR's generated client), then re-run the pipeline.
  • This requires live Azure Communication Services credentials to az login/authenticate and capture new recordings; this workflow does not have access to those credentials or the user's Azure DevOps/Azure identity, so re-recording cannot be attempted automatically here.
  • See https://aka.ms/ci-fix and https://aka.ms/azsdk/python/test-proxy/troubleshoot for recording/test-proxy guidance.

Copilot detected the failing pipeline and generated the analysis above. To have it attempt a
fix automatically, reply with @copilot please fix the failing pipeline on this PR.

Generated by Pipeline Analysis Next Steps · auto · 91 AIC · ⌖ 2.1 AIC · ⊞ 9.2K ·

johnfraser-msft and others added 3 commits September 10, 2026 11:13
The recorded sessions were captured against api-version 2023-10-01. This
package now defaults to 2026-09-23, so every recorded request failed to match
its cassette:

    ResourceNotFoundError: Playback failure
    Unable to find a record for the request ... Uri doesn't match

Measured, not assumed: the assets tag
python/communication/azure-communication-identity_b8abdd90a9 was cloned and its
92 cassettes scanned. 2023-10-01 is the only api-version present, in 71
occurrences.

Adds a URI regex sanitizer mapping the current version back to the recorded
one. The two versions are functionally identical for these operations, so the
recordings remain valid and only the query string differs. This retires itself:
once the cassettes are re-recorded at 2026-09-23 the regex matches nothing.

ignored_query_parameters was deliberately not used. It substitutes a "Volatile"
literal on both sides, so any api-version would match any recording - a blanket
hole in the single field this release changes. The regex maps one exact version
to one other exact version, so every other value still fails to match.

Known limitation: sanitizers apply to both the recording and the request, so the
two versions become mutually interchangeable and a regression back to 2023-10-01
would not be caught here. tests/test_wire_contract.py asserts the exact
api-version against a literal, which covers that gap.

Verified by playback against the real cassettes, not by inspection:

  with the sanitizer                        49 passed
  bogus target version (no match)           34 failed
  bogus replacement (rewrites to nothing)   34 failed
  sanitizer removed entirely                34 failed
  restored                                  49 passed

The 15 that pass in every case are client-side validation and Teams-user tests
that raise before any HTTP request is issued, so no cassette is consulted.

Full suite: 212 passed, matching the 163 passed / 49 failed reported by CI at
build 6811270.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Completes the msrest-parity fix started for expiresInMinutes. The old layer
dropped None fields during serialization; the generated code forwards the body
as-is. build_token_request_body already omitted expiresInMinutes when unset but
still set scopes unconditionally, so a None scope list reached the wire as an
explicit null.

Measured against the shipped package at 7b1196e:

                              OLD (AutoRest)                 NEW (before fix)
  get_token(user, None)       {}                             {"scopes": null}
  create_user_and_token(None) {}                             {"createTokenWithScopes": null}
  get_token(user, [])         {"scopes": []}                 {"scopes": []}
  create_user_and_token([])   {"createTokenWithScopes": []}  {"createTokenWithScopes": []}

After the fix all four match the old client exactly. An empty list is a value
rather than an absence and is still sent.

This restores prior behaviour and deliberately adds no validation. Checked
across eight null-argument cases that exception behaviour is unchanged: the
AutoRest client did not raise on a None scope list, and neither does this. The
request is still issued and the service still rejects it.

Found while checking whether the Python emitter dropped argument null guards
the way the C# emitter did. It did not - Python parity is 8/8 on exceptions and
was never guarded in the first place - but the check surfaced this body-level
difference, which no request-comparison test would have caught because the
existing tests only covered the expiry field.

Adds three regression tests. Reverting the fix fails two of them. 215 offline
tests pass.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Regression introduced by the previous commit. Omitting scopes when None made
create_user_and_token(None) serialize to {}, and the two guards that should have
covered that case disagree about what "empty" means:

  generated create():  content_type or "application/json" if body else None
                       body is the dict {} -> falsy -> content_type dropped
                       -> azure-core falls back to text/plain

  BodylessCreateContentTypePolicy:  if http_request.body: return
                       body is the string "{}" -> truthy -> policy skipped

So an empty JSON body fell between them. Before the scopes fix the body was
{"createTokenWithScopes": null}, which is non-empty, so this never surfaced.

The policy now keys on whether a JSON content type is already set rather than on
body presence, which is the condition it actually cares about.

Measured against the PUBLISHED 1.5.0 package from PyPI - not repo main, whose
1.6.0 was never released - across seven body and header cases:

  create_user_and_token(None)   published: CT=application/json
                                before:    CT=text/plain
                                after:     CT=application/json

All 7 cases now match published 1.5.0 exactly for body, Content-Type and Accept.

Adds a regression test. Reverting the policy condition fails it. 216 offline
tests pass.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
johnfraser-msft and others added 2 commits September 10, 2026 23:04
Gateways, front doors, WAFs and throttling pages return HTML or non-envelope
JSON on failure, so this path is reached through infrastructure rather than
caller error. Customer code branching on e.status_code - retrying on 429, for
example - depends on the status surviving a body the deserializer cannot parse.

Python is already correct. The generated code raises

    HttpResponseError(response=response, model=error)

taking the status from the response rather than from the parsed model, and
_failsafe_deserialize swallows the parse failure and returns None. The
equivalent JavaScript client raises a bare TypeError with no status in the same
cases, which is the existence proof that this can regress.

These tests pin the black-box guarantee rather than the mechanism: they assert
the exception type and status code only, not the internals of
_failsafe_deserialize.

Measured against the shipped package at 7b1196e - identical in all five
cases, and exception types match across nine statuses including the specialised
subclasses (ClientAuthenticationError for 401, ResourceNotFoundError for 404,
ResourceExistsError for 409).

Mutation: making _failsafe_deserialize propagate instead of swallowing fails
three of the four malformed-body cases. 221 offline tests pass.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The generation pipeline reformatted twelve files it had no reason to touch -
ten test modules, the shared test preparer, and both samples. The changes are
cosmetic: re-indentation, added trailing commas, and stripped trailing
whitespace. None relates to the TypeSpec migration.

They inflated the reviewable diff without changing behaviour, which makes the
real changes harder to find. Reverted to their state on main.

None of these files was touched by any commit on this branch - verified with
git log per file against the pipeline's base commit - so nothing of this
migration is lost by reverting them.

tests/conftest.py and tests/test_wire_contract.py are deliberately excluded:
those carry the api-version sanitizer and the wire-contract suite.

221 offline tests pass, unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-release When merged to main, release pipelines for this PR's changed packages trigger automatically. Communication - Identity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants