Skip to content

fix(http-client-python): raise azure-core error types for customized errors covering standard status codes#3

Closed
l0lawrence wants to merge 29 commits into
mainfrom
l0lawrence/python-custom-error-status-mapping
Closed

fix(http-client-python): raise azure-core error types for customized errors covering standard status codes#3
l0lawrence wants to merge 29 commits into
mainfrom
l0lawrence/python-custom-error-status-mapping

Conversation

@l0lawrence

Copy link
Copy Markdown
Owner

Problem

When a TypeSpec operation declares a customized error model that covers one of the standard azure-core status codes (401, 404, 409, 304), the Python emitter did not always raise the dedicated azure-core error type:

  • Ranged error (e.g. 4XX) covering a standard code → fell through to a generic HttpResponseError.
  • Default error model (covers all non-success codes) → raised the typed error (via map_error) but without the deserialized error body.

Fix

For status codes 401 → ClientAuthenticationError, 404 → ResourceNotFoundError, 409 → ResourceExistsError, 304 → ResourceNotModifiedError, the generated client now deserializes the customized error body first and then raises the dedicated azure-core error type with that body attached.

  • Ranged custom error: emit typed raises for standard codes within the range, after deserialization.
  • Default custom error: exclude the standard codes from error_map (so map_error doesn't pre-empt), deserialize the default body, then raise the typed error with the body. Codes already handled inline by a non-default error are skipped to avoid dead code.
  • Single/multi specific-code custom errors and the no-custom-error path are unchanged.

Example generated output (ranged + default)

if response.status_code not in [204]:
    map_error(status_code=response.status_code, response=response, error_map=error_map)
    error = None
    if 494 <= response.status_code <= 499:
        error = _failsafe_deserialize(_models.ErrorInRange, response)
    else:
        error = _failsafe_deserialize(_models.DefaultError, response)
    if response.status_code == 401:
        raise ClientAuthenticationError(response=response, model=error)
    if response.status_code == 404:
        raise ResourceNotFoundError(response=response, model=error)
    if response.status_code == 409:
        raise ResourceExistsError(response=response, model=error)
    if response.status_code == 304:
        raise ResourceNotModifiedError(response=response, model=error)
    raise HttpResponseError(response=response, model=error)

Validation

  • Regenerated all Azure + unbranded spector specs (181 specs, 0 failures).
  • response-status-code-range mock-api tests pass (sync + async, 4/4), exercising both an in-range code and the single 404 → ResourceNotFoundError with the custom body.
  • Added a fix changelog entry for @typespec/http-client-python.

jorgerangel-msft and others added 29 commits June 9, 2026 21:59
…nd body-root nested scenarios (microsoft#10896)

This adds python mock API coverage for new Spector scenarios introduced
by the cross-language spec updates (PR microsoft#10841): a discriminated model
with no declared subtypes, and a `@bodyRoot` parameter nested inside a
wrapper model. The PR extends existing single-discriminator tests in
both sync and async suites, adds new shared body-root tests, and aligns
local spec inputs to a version that contains the scenarios.

- **Test coverage: single-discriminator no-subtypes (shared
sync/async)**
  - Extended existing shared tests to cover:
    - `get_no_subtypes_model()`
    - `put_no_subtypes_model(...)`
- Added `Fish` model assertions to validate the expected wire payload
shape (`kind`, `size`).

- **Test coverage: body-root nested (shared sync/async)**
- Added new shared tests (`test_parameters_body_root.py` and
`asynctests/test_parameters_body_root_async.py`) covering the
`nested(...)` operation with a `BodyRootModel` (`category`, `link_type`,
`was_successful`).
  - Validated locally against the Spector mock server.

- **Spec dependency update for scenario availability**
- Updated `@typespec/http-specs` in
`packages/http-client-python/package.json` (and lockfile) to a version
containing the new scenario definitions used by regeneration.

- **Change tracking**
  - Added a Chronus `internal` entry for `@typespec/http-client-python`.

```python
def test_get_no_subtypes_model(client):
    assert client.get_no_subtypes_model() == Fish(kind="salmon", size=10)

def test_put_no_subtypes_model(client):
    client.put_no_subtypes_model(Fish(kind="salmon", size=10))

def test_nested(client):
    client.nested(BodyRootModel(category="widget", link_type="hard", was_successful=True))
```

> Note: The third scenario from PR microsoft#10841,
`Parameters_Query_SpecialChar_dollarSign`, is intentionally **not**
covered. There is an upstream spec inconsistency where `main.tsp`
declares `@route("/dollarSign")` (camelCase) while `mockapi.ts`
registers the endpoint at `/dollar-sign` (kebab-case). The mock server
only serves `/dollar-sign`, while the generated SDK correctly calls
`/dollarSign`, so the test would 404. This requires a fix in
`@typespec/http-specs` before SDK coverage can pass.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: msyyc <70930885+msyyc@users.noreply.github.com>
Co-authored-by: Yuchao Yan <yuchaoyan@microsoft.com>
microsoft#4268) (microsoft#10888)

Adds python SDK mock_api coverage for the spector cases introduced in
Azure/typespec-azure#4268. Of the two new scenarios under
`azure/client-generator-core/`, only `client-doc` is generatable by the
python emitter (`response-as-bool` is already in `SKIP_SPECS`).

### Changes
- **Tests** — sync + async tests for the `@clientDoc` scenario:
  - `harvest` POST round-trip against the mock server.
- `@clientDoc` **append** mode: `Plant` model docstring retains base doc
and appends client-specific text.
- `@clientDoc` **replace** mode: `harvest` operation docstring fully
overrides the base doc.
- Docstring assertions compare only the method/model description
(extracted via `split(":ivar")[0].strip()` for the model and
`split(":param")[0].strip()` for the operation), excluding the parameter
docstrings.
- **Changelog** — `internal` chronus entry for
`@typespec/http-client-python`.

`response-as-bool` is intentionally skipped in the emitter regeneration
config, so no client is generated and no test is added for it.

```python
def test_harvest(client: ClientDocClient):
    body = models.Plant(name="Rose", species="Rosa")
    assert client.documentation.harvest(body) == body

def test_model_doc_appended():
    # @clientdoc in append mode keeps the base @doc and appends the client-specific text.
    doc = models.Plant.__doc__.split(":ivar")[0].strip()
    assert doc == "A plant in the garden. This model is used to represent a plant in the client SDK."

def test_operation_doc_replaced(client: ClientDocClient):
    # @clientdoc in replace mode overrides the base @doc completely.
    doc = client.documentation.harvest.__doc__.split(":param")[0].strip()
    assert doc == "Retrieves a plant from the garden by submitting its name."
```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: msyyc <70930885+msyyc@users.noreply.github.com>
Co-authored-by: Yuchao Yan <yuchaoyan@microsoft.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
microsoft#10954)

## Problem

The cop static-analysis runner added in microsoft#10909 tracks the `latest` cop
release. Upstream cop advanced to **v2026.6.9.1**, which replaced the
`code.codebase('csharp')` query API with the global `provider('csharp')`
function. `code` is now a provider proxy with no `codebase` method, so
the check fails with:

`
line 18: Cannot call 'codebase' on CopProviderProxy
`

This breaks the `CSharp - Test` CI job on **every** open PR (e.g.
microsoft#10907), since CI runs cop against each PR merged with `main`.

## Fix

- **Pin** the cop release to `v2026.6.9.1` in `Invoke-Cop.ps1` instead
of tracking `latest`, so upstream cop releases can no longer break our
build. Pinning is safe because the script already vendors provider
packages from the cop repo tag reported by `cop -v`, so the providers
always match the pinned binary.
- **Migrate** `main.cop` from `code.codebase('csharp')` to `let cb :
Codebase = provider('csharp')` (the current cop API, matching the cop
`code` package samples).

Verified locally: `cop checks passed.`

Bumping the pin is now a deliberate, reviewable change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…icrosoft#10907)

The `plugins` emitter option (added in microsoft#10249) lets emitter authors load
custom generator plugins, but there was no documentation describing how
to author or use them. This adds a guide to the existing
`packages/http-client-csharp/docs`.

## Changes

- **New `docs/plugins.md`** covering:
- Plugin discovery: automatic (via `node_modules` `dist`) vs. explicit
(via the `plugins` option).
- Authoring a `GeneratorPlugin` subclass and the `CodeModelGenerator`
extension points (`AddVisitor`, `AddRewriter`, `AddMetadataReference`,
`AddSharedSourceDirectory`), plus a `LibraryVisitor` example.
- A minimal plugin `.csproj` that references the generator via a NuGet
`PackageReference` to the published
`Microsoft.TypeSpec.Generator.ClientModel` package (which transitively
brings in `Microsoft.TypeSpec.Generator`).
- `tspconfig.yaml` usage and path-resolution behavior (paths absolute or
relative to the resolved `emitter-output-dir`, auto-build of `.csproj`,
DLL scanning).
- **`emitter.md`** — `plugins` option now links to the new guide and
includes the inline path-resolution example.
- **`index.mdx`** — adds a "Generator plugins" section linking to the
doc.
- **`emitter/src/options.ts`** — expanded the `plugins` option
description to document path resolution (absolute or relative to the
resolved `emitter-output-dir`) with an inline YAML example, applying the
inline examples from microsoft#10908.
- **`readme.md`** and website reference `emitter.md` — regenerated to
reflect the updated option description.

Plugin authoring example:

```csharp
using Microsoft.TypeSpec.Generator;

public class MyPlugin : GeneratorPlugin
{
    public override void Apply(CodeModelGenerator generator)
    {
        generator.AddVisitor(new MyLibraryVisitor());
    }
}
```

```yaml
options:
  "@typespec/http-client-csharp":
    plugins:
      - "codegen/MyPlugin.dll" # file relative to emitter-output-dir
      - "codegen" # directory containing plugin assemblies
      - "/abs/path/to/MyPlugin.dll" # absolute path used as-is
```

Content was cross-checked against `GeneratorPlugin.cs`,
`GeneratorHandler.cs`, `CodeModelGenerator.cs`, and the emitter
`options.ts`/`emitter.ts`.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Co-authored-by: JonathanCrd <17486462+JonathanCrd@users.noreply.github.com>
Co-authored-by: jolov <jolov@microsoft.com>
Bumps `@azure-tools/typespec-client-generator-core` to <a
href="https://github.com/Azure/typespec-azure/blob/main/packages/typespec-client-generator-core/CHANGELOG.md#0690">0.69.0</a>
and its related dependencies for the `http-client-csharp` package, and
regenerates the test projects.

### Dependency bumps (`package.json`)
- `@azure-tools/typespec-client-generator-core`: `0.68.3` → `0.69.0`
- `@azure-tools/typespec-azure-core`: `0.68.0` → `0.69.0`
- `@azure-tools/azure-http-specs`: `0.1.0-alpha.40` → `0.1.0-alpha.42`
- `@typespec/compiler`, `@typespec/http`, `@typespec/openapi`,
`@typespec/json-schema`: `1.12.0` → `1.13.0`
- `@typespec/rest`, `@typespec/sse`, `@typespec/streams`,
`@typespec/versioning`, `@typespec/xml`, `@typespec/library-linter`:
`0.82.0` → `0.83.0`
- `@typespec/http-specs`: `0.1.0-alpha.37` → `0.1.0-alpha.38`
- `@typespec/tspd`: `0.74.2` → `0.75.0`
- `peerDependencies` ranges shifted up one minor accordingly (e.g.
azure-core/TCGC → `>=0.69.0 <0.70.0 || ~0.70.0-0`)

The TypeSpec `1.13.0`/`0.83.0` line is required transitively: TCGC
0.69.0 peers on `typespec-azure-core ^0.69.0`, which peers on
`@typespec/compiler ^1.13.0`.

### Regenerated output (`Generate.ps1`)
Generated changes reflect new spec scenarios introduced by the bumped
http-specs packages:
- New `parameters/body-root` spec project
- New `SpecialChar` sub-client under `parameters/query`
- New `Fish` base-discriminator models under
`type/model/inheritance/single-discriminator`
- Refreshed `launchSettings.json`

### Regenerated tspd docs (`regen-docs`)
Because the `@typespec/tspd` bump to `0.75.0` changed the reference-doc
output, the docs were regenerated to match (this was the source of the
generated-doc diffs flagged in CI):
- `packages/http-client-csharp/readme.md` and
`website/.../reference/emitter.md`: richer emitter-option type rendering
(`plugins` → `string[]`, `license` → object shape plus a properties
table)
- `website/.../reference/index.mdx`: removed an empty `##
TypeSpec.HttpClient` namespace section

A clean re-run of `Generate.ps1` confirmed the C# generated test-project
code has no remaining diffs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
…izing types (microsoft#10958)

## Problem

Public types are tagged with `[Experimental]` during the visitor phase
(`CSharpGen` runs visitors before `PostProcessAsync`). The
post-processor later internalizes types that are not reachable from the
public API surface, but `MarkInternal` only changed the `public` ->
`internal` modifier token and left the already-written `[Experimental]`
attribute in place. The result was a public-API stability attribute on
`internal` types (e.g. `InternalProjectsClientOptions` and various
model-factory internals), which is meaningless on non-public types and
produces spurious diff churn.

## Fix

`MarkInternal` now also strips the `[Experimental]`
(`System.Diagnostics.CodeAnalysis.ExperimentalAttribute`) attribute when
internalizing a type:

- Matches both `Experimental` and `ExperimentalAttribute`, including
qualified names.
- Preserves other attributes (e.g. trims a combined `[Serializable,
Experimental]` list down to `[Serializable]`).
- Re-attaches the declaration's original leading trivia so documentation
comments and indentation are preserved (the internalize pass is not
reformatted afterward).

### Logging

- `Debug`: `Internalizing unreferenced public type '<name>'.`
- `Debug`: `Removed [Experimental] attribute from '<name>' while
internalizing it.`
- `Info`: `Internalized N unreferenced public type(s).`

## Tests

New `PostProcessorTests.RemovesExperimentalAttributeWhenInternalizing`
covering:
- referenced (public) type keeps `[Experimental]`;
- unreferenced type is internalized and loses `[Experimental]`, doc
comment preserved;
- other attribute preserved when in a separate list;
- other attribute preserved when combined in the same list.

Full `Microsoft.TypeSpec.Generator` suite passes (1526 passed, 0
failed).

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…API (microsoft#10953)

`mvn compile test` failed in both Java test modules because
`parameters/query/QueryTests` still referenced removed `QueryClient`
construction paths. This updates the tests to use the currently
generated query client surface.

- **What changed**
  - Updated `QueryTests` in both modules:
    - `generator/http-client-generator-test`
    - `generator/http-client-generator-clientcore-test`
- Replaced obsolete `QueryClient` instantiation with `ConstantClient`
from `QueryClientBuilder.buildConstantClient()`.

- **Why this resolves the issue**
- The generated `parameters.query` package exposes
`ConstantClient`/`SpecialCharClient` builders, not a `QueryClient` type
or `buildClient`/`buildQueryClient` methods.
  - Tests now target the actual generated API contract.

- **Code change example**
  ```java
  // before
private final QueryClient client = new
QueryClientBuilder().buildClient();

  // after
private final ConstantClient client = new
QueryClientBuilder().buildConstantClient();
  ```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: weidongxu-microsoft <53292327+weidongxu-microsoft@users.noreply.github.com>
Co-authored-by: Weidong Xu <weidxu@microsoft.com>
…osoft#10961)

`QueryTests.testDollarSign` is failing in Java because the fix lives in
`@typespec/http-specs` and is not yet available through the released
package consumed by the Java test projects. This PR keeps the Java
branch releasable by removing the unreleased route workaround and
temporarily disabling the affected tests.

- **Problem**
- The Java query tests exercise the `$filter` dollar-sign scenario
against the published `@typespec/http-specs` package, which still
contains the broken route.
- Keeping the route fix in this branch would only patch local sources
and generated code, not the package version Java actually consumes.

- **Changes**
- Reverted the temporary `http-specs` route and generated-path edits
from this branch.
- Added targeted `@Disabled` annotations to `QueryTests.testDollarSign`
in both Java test suites:
    - `http-client-generator-test`
    - `http-client-generator-clientcore-test`

- **Scope**
  - Leaves the rest of the query coverage intact.
- Isolates the workaround to the two known failing tests until the
`http-specs` fix is published and can be pulled into Java.

- **Example**
  ```java
  @test
@disabled("Blocked until @typespec/http-specs publishes the dollar-sign
route fix")
  public void testDollarSign() {
      specialCharClient.dollarSign("status eq 'active'");
  }
  ```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: weidongxu-microsoft <53292327+weidongxu-microsoft@users.noreply.github.com>
Co-authored-by: Weidong Xu <weidxu@microsoft.com>
…rosoft#10959)

Bumps the pinned Agent Cop release used by `eng/scripts/Invoke-Cop.ps1`
from `v2026.6.9.1` to the latest release `v2026.6.10.1`.

Verified locally against a clean `main` checkout: the new binary
downloads, providers seed at the matching tag, and the `cop-checks/`
rules run clean (`cop checks passed.`).

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…essed without a replacement (microsoft#10950)

Convenience methods call into their protocol method, so when a client
author suppresses the protocol methods via `[CodeGenSuppress]`, the
generated convenience methods no longer compile. They should be skipped
— unless the protocol method is replaced by custom code with the same
signature, in which case the convenience method still compiles and
should be kept.

Paging convenience methods are an exception: they instantiate the
collection result directly instead of calling the protocol method, so
they are always generated (along with their paging helpers) regardless
of protocol-method suppression.

### Changes (`http-client-csharp`)

- **`MethodProvider.IsMethodSuppressed()`** — a focused instance
predicate that returns `true` only when the method's signature is
suppressed by a `[CodeGenSuppress]` attribute on its enclosing type. It
no longer makes the full keep/skip decision by itself (the
custom-replacement check lives in the caller). The predicate lives in
the Generator assembly so the `[CodeGenSuppress]` matching helpers can
stay non-public: `TypeProvider.GetMemberSuppressionAttributes` and the
method `IsMatch` overload are now `internal` (previously the matching
had to be reached through a public `TypeProvider.IsMethodSuppressed`).
The predicate itself is `public` because `ScmMethodProviderCollection`
(its caller) is not a `MethodProvider` subclass and there is no
`InternalsVisibleTo` from the Generator assembly to the production
`Microsoft.TypeSpec.Generator.ClientModel` assembly, so `protected
internal` is not reachable from the call site.
- **`ScmMethodProviderCollection.ProtocolMethodExists(MethodProvider
generatedProtocolMethod)`** — decides whether each convenience method
(sync/async) is generated. The protocol method is considered to exist
(so the convenience method is kept) unless it was suppressed **and** the
client's custom code provides no non-partial replacement with the same
signature. The check reads `EnclosingType.CustomCodeView?.Methods`
directly rather than enumerating `CanonicalView.Methods`, because the
latter rebuilds the client's methods while they are being built, causing
infinite recursion.
- **`ScmMethodProviderCollection.BuildMethods`** — gates each
convenience method on `_pagingServiceMethod != null ||
ProtocolMethodExists(protocolMethod)`. Paging convenience methods don't
call the protocol method (they instantiate the
`CollectionResultDefinition` directly via `new {collection}(this,
...)`), so suppressing the protocol method does not break them and they
are always generated. This also ensures the paging helpers — including
the typed `...CollectionResultOfT` collection-result definition, which
is only created during convenience-method building — continue to be
emitted so that custom code referencing them keeps compiling.

### Behavior

```csharp
// Protocol suppressed, no replacement -> convenience method skipped (would not compile)
[CodeGenSuppress("HelloAgain", typeof(RequestOptions))]
public partial class TestClient { }

// Protocol suppressed but replaced in custom code -> convenience method still generated
[CodeGenSuppress("HelloAgain", typeof(RequestOptions))]
public partial class TestClient
{
    public virtual ClientResult HelloAgain(RequestOptions options) { ... }
}

// Protocol suppressed but only customized with an overload that has an extra parameter
// (different signature) -> convenience method still skipped (no matching replacement)
[CodeGenSuppress("HelloAgain", typeof(RequestOptions))]
public partial class TestClient
{
    public virtual ClientResult HelloAgain(string extra, RequestOptions options) { ... }
}

// Paging protocol suppressed -> paging convenience methods AND collection-result helpers
// are still generated (the convenience method instantiates the collection directly)
[CodeGenSuppress("GetItems", typeof(RequestOptions))]
public partial class TestClient { }
```

### Tests

Added to `ClientProviderCustomizationTests`:
- `SuppressedProtocolMethodSkipsConvenienceMethod` — suppressed, no
replacement → no convenience methods.
- `SuppressedProtocolMethodWithCustomCodeKeepsConvenienceMethod` —
suppressed + custom replacement → convenience methods retained,
generated protocol overloads dropped. Each generated convenience method
is written with `CodeWriter.WriteMethod` and the entire method
(signature + body) is validated against TestData golden files.
- `SuppressedProtocolMethodWithCustomOverloadSkipsConvenienceMethod` —
suppressed + custom overload with an additional parameter (different
signature) → not treated as a replacement, so the convenience method is
still skipped.
- `SuppressedPagingProtocolMethodKeepsPagingHelpers` — paging protocol
methods suppressed via custom code that references the paging helper →
both the paging convenience methods and all collection-result helpers
(`...CollectionResult`, `...AsyncCollectionResult`,
`...CollectionResultOfT`, `...AsyncCollectionResultOfT`) are still
generated.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
…osoft#10967)

The C# emitter does not support `multipart/mixed` requests, yet since
the addition of `multipart/form-data` support it would emit an incorrect
convenience method for them. This disables convenience method generation
for multipart content types other than `multipart/form-data` and
surfaces a diagnostic instead.

The detection lives in the emitter so the generator simply honors the
resulting `generateConvenienceMethod` flag.

### Changes

- **`operation-converter.ts`**: In `fromSdkServiceMethodOperation`, when
an operation uses a `multipart/*` content type other than
`multipart/form-data`, `generateConvenienceMethod` is set to `false`
(protocol methods still emitted) and a warning diagnostic is reported. A
small `isUnsupportedMultipart` helper inspects the request media types.
- **`lib.ts`**: Added the `unsupported-multipart-convenience-method`
warning diagnostic.
- **Tests**: Added emitter unit tests in `operation-converter.test.ts` —
`multipart/mixed` turns off convenience method generation and emits the
warning, while `multipart/form-data` keeps convenience methods with no
diagnostic.

```ts
const requestMediaTypes = getRequestMediaTypes(method.operation);
if (generateConvenience && isUnsupportedMultipart(requestMediaTypes)) {
  diagnostics.add(
    createDiagnostic({
      code: "unsupported-multipart-convenience-method",
      format: { methodCrossLanguageDefinitionId: method.crossLanguageDefinitionId },
      target: method.__raw ?? NoTarget,
    }),
  );
  generateConvenience = false;
}
```

No existing test specs use `multipart/mixed`, so generated library
output is unchanged.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Updated
[MessagePack](https://github.com/MessagePack-CSharp/MessagePack-CSharp)
from 2.5.192 to 2.5.301.

<details>
<summary>Release notes</summary>

_Sourced from [MessagePack's
releases](https://github.com/MessagePack-CSharp/MessagePack-CSharp/releases)._

## 2.5.301

## Security release

This release fixes 2 high severity and 9 moderate severity security
vulnerabilities as listed below.

This release is missing #​2269 from the v2.5.205 release. We recommend
folks adopt the v2.5.302 release which has all the security fixes
combined.

### High severity advisory fixes

- 696b4a76 GHSA-vh6j-jc39-fggf Use iteration for skipping msgpack
structures for CWE-674
- 3538bc11 GHSA-hv8m-jj95-wg3x Bound LZ4 input reads for CWE-125

### Moderage severity advisory fixes

- 853429a0 GHSA-v72x-2h86-7f8m Guard LZ4 decompression length for
CWE-409
- 826f17c7 GHSA-qhmf-xw27-6rqr Reject nested typeless blocklist bypass
for CWE-502
- c98d31f2 GHSA-2f33-pr97-265q Default MVC input formatter to
UntrustedData for CWE-1188
- ae90f2b1 GHSA-2x83-8g95-xh59 Limit untrusted ExpandoObject maps for
CWE-407
- 940b8508 GHSA-wfr3-xj75-pfwh Guard dynamic union depth for CWE-674
- e01f07cf GHSA-w567-gjr2-hm5j Validate Unity blit lengths for CWE-789
- dc6f6324 GHSA-cxmj-83gh-fp49 Fix CWE-789 multidimensional array
allocation validation
- e97f71e7 GHSA-q2h6-ghwm-5qm8 Use secure lookup comparer for CWE-407
- 7b12e5b5 GHSA-cj9g-3mj2-g8vv Guard JSON conversion depth for CWE-674
- a3c8a183 GHSA-cj9g-3mj2-g8vv Avoid JSON separator recursion for
CWE-674
- 96743523 GHSA-cj9g-3mj2-g8vv Guard typeless JSON depth for CWE-674

### Fixes with no security advisory

- 814bc4c1 Honor TypeFormatter options hooks for CWE-470
- b0f8c5e2 Fix WriteRawX methods to advance by written length
- 0124048c Fix CWE-190 map header length overflow


## 2.5.205

## What's Changed

* Fix repo url by @​tomap in
MessagePack-CSharp/MessagePack-CSharp#2065
* Update DynamicAssembly usage to honor different AssemblyLoadContext's
by @​BertanAygun in
MessagePack-CSharp/MessagePack-CSharp#2183
* Add more types to the default disallow list of named types to be
deserialized by @​AArnott in
MessagePack-CSharp/MessagePack-CSharp#2263
* Add several known unsafe 'gadgets' to the disallow list by @​AArnott
in MessagePack-CSharp/MessagePack-CSharp#2269

## New Contributors
* @​tomap made their first contribution in
MessagePack-CSharp/MessagePack-CSharp#2065

**Full Changelog**:
MessagePack-CSharp/MessagePack-CSharp@v2.5.192...v2.5.205

## 2.5.198

## What's Changed
* Fix repo url by @​tomap in
MessagePack-CSharp/MessagePack-CSharp#2065
* Update DynamicAssembly usage to honor different AssemblyLoadContext's
by @​BertanAygun in
MessagePack-CSharp/MessagePack-CSharp#2183

## New Contributors
* @​tomap made their first contribution in
MessagePack-CSharp/MessagePack-CSharp#2065

**Full Changelog**:
MessagePack-CSharp/MessagePack-CSharp@v2.5.192...v2.5.198

Commits viewable in [compare
view](MessagePack-CSharp/MessagePack-CSharp@v2.5.192...v2.5.301).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=MessagePack&package-manager=nuget&previous-version=2.5.192&new-version=2.5.301)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/microsoft/typespec/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…cks (microsoft#10955)

## Why

Fixes microsoft#10314. When a property or parameter description ended with a code
block, the emitter appended annotations like `Required.` to the very end
of the string. With code blocks converted to RST `.. code-block::`, the
annotation landed right after the closing `]` of a JSON block (`].
Required.`), which breaks Sphinx rendering.

## Approach

Annotations are added centrally in `add_to_description` (in
`pygen/codegen/models/utils.py`), used by both `property.py` and
`parameter.py` and other callers. That helper is now code-block aware:
when the description contains `.. code-block::`, the annotation is
inserted into the prose **before** the code block instead of being
appended after it. Behavior is unchanged when there is no code block.

## Tests

Added `tests/unit/test_add_to_description.py` covering the empty, plain,
single-code-block, and multiple-code-block cases.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Yuchao Yan <yuchaoyan@microsoft.com>
…icrosoft#10971)

## Summary

Adds a new `disable-roslyn-reduce` boolean emitter option to the C#
emitter. When set to `true`, the generator skips the Roslyn
`Simplifier.ReduceAsync` post-processing step. This is useful for
iterating more quickly during development, and is something we may want
to expose in the TypeSpec playground as well.

The option defaults to `false`, so existing behavior is unchanged.

## Changes

- `emitter/src/options.ts` — add `disable-roslyn-reduce` to
`CSharpEmitterOptions` and its JSON schema.
- `emitter/src/type/configuration.ts` — add the option to the
`Configuration` type.
- `emitter/src/emitter.ts` — thread the option into the generated
`Configuration.json`.
- `generator/Microsoft.TypeSpec.Generator/src/Configuration.cs` — parse
the option (`DisableRoslynReduce`).
-
`generator/Microsoft.TypeSpec.Generator/src/PostProcessing/GeneratedCodeWorkspace.cs`
— skip `Simplifier.ReduceAsync` when enabled.
- Docs (`docs/emitter.md`, `readme.md`) and unit tests updated.

## Performance data

Measured by running the generator (`Microsoft.TypeSpec.Generator.exe`)
directly against saved code models, after a warmup, reduce step on
(default) vs. off (`disable-roslyn-reduce: true`):

| Spec | Reduce on (avg s) | Reduce off (avg s) | Improvement |
| --- | --- | --- | --- |
| `Sample-TypeSpec` (5 runs) | 21.79 | 11.99 | ~45% faster |
| `type/property/additional-properties` (3 runs) | 5.58 | 3.61 | ~35%
faster |
| `type/property/value-types` (3 runs) | 4.50 | 3.17 | ~30% faster |
| `special-words` (3 runs) | 4.53 | 3.37 | ~26% faster |
| `type/file` (3 runs) | 0.96 | 1.04 | negligible* |

\* `type/file` has a large code model but generates very little code, so
the reduce step is not a meaningful portion of its runtime; the
difference is within run-to-run noise.

The more code a library generates, the larger the win —
`Sample-TypeSpec` (a large, code-heavy project) sees roughly a 45%
reduction in generation time.

## Testing

- `ConfigurationTests` (added `DisableRoslynReduce_ParsedFromConfig` /
`_DefaultsToFalse`) — 24 passed.
- Emitter `options.test.ts` extended — 6 passed.
- `npm run build` (emitter + generator + api-extractor) succeeds.

--generated by Copilot

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… providers (microsoft#10981)

Derived C# generators (e.g. Azure management-plane) need to register
generator-specific custom-code attributes such as
`CodeGenResourceDataAttribute` that are emitted into generated SDK
projects and available during custom-code compilation. The base
generator's `CustomCodeAttributeProviders` list was not extensible,
forcing downstream generators to use reflection.

## Changes

- **`CodeModelGenerator.CustomCodeAttributeProviders`**: remains
`internal`, now backed by a mutable list still pre-seeded with the four
built-in definitions
(`CodeGenType`/`Member`/`Suppress`/`Serialization`).
- **`AddCustomCodeAttributeProvider(TypeProvider)`**: new `protected`
method letting derived generators contribute their own attribute
definitions. Registered providers flow through the existing
`Configure()` → `AddTypeToKeep` path and into
`OutputLibrary`/`CSharpGen` custom-code compilation — no reflection, no
SDK dependency on the generator assembly.
- **Tests**:
- `GeneratorTests` cover the default provider count and appending via
the new method (`TestGenerator` exposes the protected method for
testing).
-
`ModelCustomizationTests.CanReadCustomCodeAttributeFromRegisteredProvider`
is an end-to-end test that contributes a sample attribute provider
through the extension point, references that attribute in TestData
custom code on a partial model, emits the contributed definition into
the custom-code compilation, and validates that the parsed
`ModelProvider.CustomCodeView` registers the attribute (type, namespace,
and argument count). Adds a `TestCustomCodeAttributeDefinition` helper
and a TestData fixture.

## Usage

```csharp
protected override void Configure()
{
    base.Configure();
    AddCustomCodeAttributeProvider(new CodeGenResourceDataAttributeDefinition());
}
```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
microsoft#10844)

- after polyfill plugin was removed, Python emitter is no longer browser
bundleable due to Node or filesystem imports
- extract Node calls into a separate file and swap for browser vs.
non-browser

local validation:
- Works in browser: from the `typespec-azure` repo, overrode and
installed this branch's http-client-python and checked that
`/typespec-azure-playground-website` is able to start when including
`typespec-python`

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…icrosoft#10962)

The changelog entry for the dollar-sign query route fix was marked as
`internal` but should be `fix` — the change corrects a bug where the
TypeSpec `@route` path didn't match the mock API URI, causing SDK test
404s.

## Changes
- Updated `.chronus/changes/http-specs-fix-dollar-sign-route-*.md`:
`changeKind: internal` → `changeKind: fix`

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: weidongxu-microsoft <53292327+weidongxu-microsoft@users.noreply.github.com>
… (python) (microsoft#10947)

# Overview:
Other language emitters have fully support this feature and this feature
belongs to `core` features in spec dashboard.

## PR description

Adds support in `@typespec/http-client-python` for SDK users to pass
`datetime.timedelta` for durations encoded as `seconds`/`milliseconds`
(in addition to the existing `ISO8601` support), and extends the
`encode/duration` mock_api test coverage to exercise this.

## Changes

### Feature: timedelta support for seconds/milliseconds durations

- **Emitter** (`emitter/src/types.ts`): `emitBuiltInType` now emits
`seconds`/`milliseconds` `DurationKnownEncoding` values as a `duration`
type carrying the `encode` and numeric `wireType`, alongside the
existing `ISO8601` branch.
- **Generator** (`generator/pygen/codegen/models/primitive_types.py`):
`DurationType` reads `encode` + `wireType` and produces a combined
format token `duration-{seconds|milliseconds}-{int|float}`; `ISO8601`
retains the legacy `duration` behavior.
- **Runtime serialization/deserialization** (both paths):
- `model_base.py.jinja2` (DPG body model properties): added
`_serialize_duration` plus seconds/milliseconds deserializers and the
corresponding `_DESERIALIZE_MAPPING_WITHFORMAT` entries.
- `serialization.py.jinja2` (msrest query/header params): added
serialize/deserialize methods for the seconds/milliseconds (int/float)
formats, registered in the type maps.

This lets users pass `datetime.timedelta` and receive
`datetime.timedelta` back for these encodings, with conversion to/from
the numeric wire value handled by the runtime.

### Test coverage

- **Added scenario coverage** across all three operation groups
(`query`, `property`, `header`), now using `datetime.timedelta` input:
  - `milliseconds` encodings (`int32`, `float`, `float64`)
  - `larger-unit` encodings (`int32`/`float` seconds and milliseconds)
  - `milliseconds` arrays
- **Files** (sync + async, both flavors):
- `tests/mock_api/azure/test_encode_duration.py`,
`tests/mock_api/azure/asynctests/test_encode_duration_async.py`
- `tests/mock_api/unbranded/test_encode_duration.py`,
`tests/mock_api/unbranded/asynctests/test_encode_duration_async.py`
- **Property assertions** use the correct per-scenario models (e.g.
`Float64SecondsDurationProperty`,
`Int32MillisecondsLargerUnitDurationProperty`) and assert
`datetime.timedelta` on responses.
- **Changelog** entry under `.chronus/changes` (`changeKind: feature`).

Example of newly-covered cases using `datetime.timedelta`:

```python
client.query.int32_milliseconds_array(
    input=[datetime.timedelta(milliseconds=36000), datetime.timedelta(milliseconds=47000)]
)
client.header.float_milliseconds_larger_unit(duration=datetime.timedelta(milliseconds=210000))
result = client.property.int32_milliseconds_larger_unit(
    Int32MillisecondsLargerUnitDurationProperty(value=datetime.timedelta(milliseconds=180000))
)
assert result.value == datetime.timedelta(milliseconds=180000)
```

## Testing

- ✅ Regenerated `encode/duration` for both azure and unbranded flavors;
verified generated models use `datetime.timedelta` with the new format
tokens
- ✅ mock_api suites pass against the live mock server (azure +
unbranded, sync + async — 12 passing)

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: msyyc <70930885+msyyc@users.noreply.github.com>
Co-authored-by: Yuchao Yan <yuchaoyan@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…n scenario (microsoft#10986)

Adds Python SDK mock API coverage for the
`Parameters_Query_SpecialChar_dollarSign` Spector scenario
introduced/fixed in microsoft#10962 (route corrected from
`/dollarSign` to `/dollar-sign`).

### Changes
- **Spec bump**: `@typespec/http-specs` `0.1.0-alpha.38` →
`0.1.0-alpha.39-dev.1`, the first published version carrying the
`/dollar-sign` route fix (peer deps verified compatible).
- **Tests**: Added sync + async `test_special_char_dollar_sign` to the
shared `parameters/query` test files, exercising the generated
`special_char.dollar_sign` operation.
- **Changelog**: `internal` entry for `@typespec/http-client-python`.

```python
def test_special_char_dollar_sign(client: QueryClient):
    client.special_char.dollar_sign(filter="status eq 'active'")
```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: msyyc <70930885+msyyc@users.noreply.github.com>
…equest (microsoft#10957)

## Bug

For paging operations whose request body is a flattened JSON model, the
generated client raised `UnboundLocalError: cannot access local variable
'body'` on the first call. The body construction block was emitted
inside the `prepare_request` closure, and since `body` is assigned
there, Python treats it as a function-local for the whole closure, so
the earlier `if body is _Unset:` read fails before it is ever bound.

## Fix

Construct the JSON model body once in the enclosing method scope (next
to where overload body initialization already lives) and before the body
is serialized into the request content. The `prepare_request` closure
then only reads the already-built body. This mirrors the existing
pattern where `_initialize_overloads` returns early for paging so body
setup happens once outside the closure.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ests (microsoft#10992)

## Description

Use specific exception types in the status code range mock_api tests
instead of the generic `Exception`, for both sync and async variants.

- `test_error_response_status_code_in_range` now asserts on
`core_library.exceptions.HttpResponseError`
- `test_error_response_status_code_404` now asserts on
`core_library.exceptions.ResourceNotFoundError`
- Applied consistently to both the sync test and its async counterpart

A changelog entry was added under `.chronus/changes`.
…#10995)

OpenAPI import currently drops parameter location metadata for `in:
cookie`, producing undecorated parameters in generated TypeSpec. This
updates conversion so cookie parameters are emitted as HTTP cookie
parameters across OpenAPI 3.0/3.1/3.2 nullable forms.

- **Converter fix**
- Added `cookie` to supported parameter locations in the OpenAPI3
converter decorator mapping.
- Cookie parameters now generate `@cookie` the same way `query`,
`header`, and `path` already do.

- **Coverage updates**
- Extended parameter-location tests to include `cookie` in top-level
parameter conversion.
  - Added operation-level cookie tests covering:
    - OpenAPI 3.0: `nullable: true`
    - OpenAPI 3.1/3.2: `type: ["string", "null"]`
    - required vs optional parameter emission

- **Changelog**
  - Added a `fix` chronus entry for `@typespec/openapi3`.

```tsp
// before
@get op Widgets_get(session_id?: string | null): OkResponse;

// after
@get op Widgets_get(@cookie session_id?: string | null): OkResponse;
```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
microsoft#10835)

Existing `encode/duration` scenarios only used whole-number payloads, so
they couldn't catch the bug from microsoft#10831 where a `duration` with a
fractional sub-second component was serialized as a floating point
number (e.g. `123.45`) instead of an integer.

These tests target the *lossy encode* case, where the source `duration`
carries more precision than the target integer encoding can represent.
The client must still serialize the value using the target number type
(an integer), discarding the extra precision, rather than emitting a
floating point number. This is distinct from arbitrary type mismatches,
which are already covered by the existing round-trip scenarios.

### Changes (`packages/http-specs/specs/encode/duration/`)

- **`main.tsp`**: New dedicated `Lossy` namespace (routed under
`/encode/duration/lossy/...`) containing the lossy-encode scenarios,
instead of placing them under the regular `Query`/`Property`/`Header`
encoding categories. For each transport (query, property, header) it
adds:

- `int32-seconds`: a `36.25`-second duration encoded as `int32` seconds
(sub-second source precision).
- `int32-milliseconds`: a `36250.25`-millisecond duration encoded as
`int32` milliseconds (sub-millisecond source precision).

  ```typespec
  @route("/int32-seconds")
  @Scenario
  @scenarioDoc("""
...The duration is 36.25 seconds, e.g. TimeSpan.FromSeconds(36.25) in
C#.
The client must serialize the value as an integer (not a floating point
    number such as `36.25`), discarding the sub-second precision.
Because emitters may floor, round, or ceil when discarding that
precision,
    the expected query parameter is `input=36` or `input=37`.
    """)
  op int32Seconds(
@query @encode(DurationKnownEncoding.seconds, int32) input: duration,
  ): NoContentResponse;
  ```

- **`mockapi.ts`**: New handlers (`createLossyBodyServerTests`,
`createLossyQueryServerTests`, `createLossyHeaderServerTests`) verify
that the received value is serialized as an integer (rejecting
float/double/decimal output). They accept an allow-list of integers
covering floor, round, **and** ceil results (`36`/`37` for seconds,
`36250`/`36251` for milliseconds), so the test verifies the core
contract ("serializes as an int") without taking a position on an
emitter's rounding mode.

- **`spec-summary.md`**: Regenerated.

### Note

The mock validation accepts floor/round/ceil results rather than a
single exact value, so it remains agnostic to an emitter's rounding mode
while still failing on floating point output.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Co-authored-by: jolov <jolov@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…errors covering standard status codes

When a customized error model covers one of the standard azure-core status codes (401, 404, 409, 304) via a ranged or default error response, deserialize the error body and raise the dedicated azure-core error type (e.g. ClientAuthenticationError) with that customized body, instead of falling back to a generic HttpResponseError or raising without a body.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@l0lawrence l0lawrence closed this Jun 16, 2026
@github-actions

Copy link
Copy Markdown

❌ There is undocummented changes. Run chronus add to add a changeset or click here.

The following packages have changes but are not documented.

  • typespec-vs

The following packages have already been documented:

  • @typespec/http-client-java
  • @typespec/http-client-python
  • @typespec/http-specs
  • @typespec/openapi3
Show changes

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

Support datetime.timedelta for duration types encoded as seconds or milliseconds. SDK users can now pass a datetime.timedelta (instead of a raw int/float) and responses are deserialized back into datetime.timedelta.

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

Add sync and async mock_api tests for the service/multiple-services Spector scenario and enable its regeneration.

@typespec/http-specs - internal ✏️

Add encode/duration lossy Spector scenarios verifying a duration whose value carries more precision than the target integer encoding (fractional seconds and sub-millisecond milliseconds) is serialized as an integer

@typespec/openapi3 - fix ✏️

Fix OpenAPI import to emit @cookie decorators for cookie parameters, including nullable and type-null schema variants.

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

Fix UnboundLocalError for paging operations with a flattened JSON model body. The request body is now constructed once outside the prepare_request callback (and before the body is serialized into the request content) instead of inside the closure, where assigning body made it an unbound local on every page fetch.

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

Fix Sphinx docstring rendering when a Required. (or other) annotation followed a code block. The annotation is now inserted into the prose before the code block instead of being appended after it.

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

Use specific exception types in status code range mock_api tests for sync and async

@typespec/http-client-java - internal ✏️

Add e2e tests for parameters/body-root, parameters/query special char, type/model/inheritance/single-discriminator no-subtypes, azure/resourcemanager/common-properties arm-resource-identifiers, and azure/resourcemanager/management-group scenarios

@typespec/http-client-java - dependencies ✏️

Update Node.js dependencies to latest (compiler 1.13.0, TCGC 0.69.0, azure-core 0.69.0) and bump version to 0.9.0

@typespec/http-specs - fix ✏️

Fix the dollar-sign query scenario route to match the mock API.

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

Add sync and async mock_api tests for the management group scoped resources and ARM resource identifier Spector scenarios from azure-http-specs.

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

Add mock API test for the Parameters_Query_SpecialChar_dollarSign Spector scenario.

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

Raise the dedicated azure-core error type for standard status codes (401, 404, 409, 304) whenever a customized error model covers them (ranged or default error responses), instead of falling back to a generic HttpResponseError or raising without the error body. The error body is now deserialized into the customized error model first and attached to the raised error. For example, a 401 covered by a custom error model now raises ClientAuthenticationError with the customized error body shape.

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

Refactor Node usage in Python emitter to make it browser bundleable

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants