From 694d9291804d642440f7f7f9aa54b398ad7867bf Mon Sep 17 00:00:00 2001 From: Libba Lawrence Date: Tue, 11 Aug 2026 11:16:07 -0700 Subject: [PATCH 1/2] fix(http-client-python): preserve encoded client types Preserve supported client-facing types when TCGC supplies wire types for boolean, integer, and byte encodings. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f0bffcdc-e290-4621-980a-834a1e67bdc2 --- .../fix-python-wire-encoding-2026-08-11.md | 7 ++ .../http-client-python/emitter/src/types.ts | 15 +++- .../emitter/test/types.test.ts | 72 +++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 .chronus/changes/fix-python-wire-encoding-2026-08-11.md create mode 100644 packages/http-client-python/emitter/test/types.test.ts diff --git a/.chronus/changes/fix-python-wire-encoding-2026-08-11.md b/.chronus/changes/fix-python-wire-encoding-2026-08-11.md new file mode 100644 index 00000000000..55fca413747 --- /dev/null +++ b/.chronus/changes/fix-python-wire-encoding-2026-08-11.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-client-python" +--- + +Preserve Python boolean, integer, and bytes client types when using supported string, base64, or base64url wire encodings. diff --git a/packages/http-client-python/emitter/src/types.ts b/packages/http-client-python/emitter/src/types.ts index 617f26f62cf..ea3e7febab3 100644 --- a/packages/http-client-python/emitter/src/types.ts +++ b/packages/http-client-python/emitter/src/types.ts @@ -478,6 +478,7 @@ function emitBuiltInType( context: PythonSdkContext, type: SdkBuiltInType | SdkDurationType | SdkDateTimeType, ): Record { + const pythonType = sdkScalarKindToPythonKind[type.kind] || type.kind; if (type.encode) { if (type.kind === "duration") { if (type.encode === "ISO8601") { @@ -509,7 +510,17 @@ function emitBuiltInType( } } - // fallback to wire type for unknown or unsupported encode + if ( + (type.encode === "string" && (type.kind === "boolean" || pythonType === "integer")) || + (type.kind === "bytes" && (type.encode === "base64" || type.encode === "base64url")) + ) { + return getSimpleTypeResult(context, { + type: pythonType, + encode: type.encode, + }); + } + + // Python cannot apply unknown/custom encodings, so expose the wire type instead of silently ignoring the encoding. if ("wireType" in type && type.wireType !== undefined) { return getSimpleTypeResult(context, { type: sdkScalarKindToPythonKind[type.wireType.kind] || type.wireType.kind, @@ -519,7 +530,7 @@ function emitBuiltInType( } return getSimpleTypeResult(context, { - type: sdkScalarKindToPythonKind[type.kind] || type.kind, // TODO: switch to kind + type: pythonType, // TODO: switch to kind encode: type.encode, }); } diff --git a/packages/http-client-python/emitter/test/types.test.ts b/packages/http-client-python/emitter/test/types.test.ts new file mode 100644 index 00000000000..750c357a670 --- /dev/null +++ b/packages/http-client-python/emitter/test/types.test.ts @@ -0,0 +1,72 @@ +import type { SdkBuiltInType } from "@azure-tools/typespec-client-generator-core"; +import { deepStrictEqual } from "assert"; +import { describe, it } from "vitest"; +import type { PythonSdkContext } from "../src/lib.js"; +import { getType } from "../src/types.js"; + +function createBuiltInType( + kind: SdkBuiltInType["kind"], + encode?: string, + wireType?: SdkBuiltInType, +): SdkBuiltInType { + return { + kind, + name: kind, + crossLanguageDefinitionId: `TypeSpec.${kind}`, + decorators: [], + encode, + wireType, + }; +} + +function emitBuiltInType(type: SdkBuiltInType): Record { + const context = { + __simpleTypesMap: new Map(), + } as PythonSdkContext; + return getType(context, type); +} + +describe("typespec-python: built-in types", () => { + it("preserves boolean encoded as string", () => { + deepStrictEqual( + emitBuiltInType(createBuiltInType("boolean", "string", createBuiltInType("string"))), + { + type: "boolean", + encode: "string", + }, + ); + }); + + it.each(["safeint", "uint32", "uint8"] as const)( + "preserves %s encoded as string as an integer", + (kind) => { + deepStrictEqual( + emitBuiltInType(createBuiltInType(kind, "string", createBuiltInType("string"))), + { + type: "integer", + encode: "string", + }, + ); + }, + ); + + it.each(["base64", "base64url"] as const)("preserves bytes encoded as %s", (encode) => { + deepStrictEqual( + emitBuiltInType(createBuiltInType("bytes", encode, createBuiltInType("string"))), + { + type: "bytes", + encode, + }, + ); + }); + + it("falls back to the wire type for a custom encoding", () => { + deepStrictEqual( + emitBuiltInType(createBuiltInType("string", "abc", createBuiltInType("int32"))), + { + type: "integer", + encode: "abc", + }, + ); + }); +}); From 2b11e89ff4d15144e77edea4d16dfec206941bdf Mon Sep 17 00:00:00 2001 From: Libba Lawrence Date: Tue, 11 Aug 2026 12:14:22 -0700 Subject: [PATCH 2/2] refactor(http-client-python): use lookup for supported encodings Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f0bffcdc-e290-4621-980a-834a1e67bdc2 --- packages/http-client-python/emitter/src/types.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/http-client-python/emitter/src/types.ts b/packages/http-client-python/emitter/src/types.ts index ea3e7febab3..4b099e05c5c 100644 --- a/packages/http-client-python/emitter/src/types.ts +++ b/packages/http-client-python/emitter/src/types.ts @@ -474,6 +474,12 @@ const sdkScalarKindToPythonKind: Record = { azureLocation: "string", }; +const supportedPythonEncodings = new Map>([ + ["boolean", new Set(["string"])], + ["integer", new Set(["string"])], + ["bytes", new Set(["base64", "base64url"])], +]); + function emitBuiltInType( context: PythonSdkContext, type: SdkBuiltInType | SdkDurationType | SdkDateTimeType, @@ -510,10 +516,7 @@ function emitBuiltInType( } } - if ( - (type.encode === "string" && (type.kind === "boolean" || pythonType === "integer")) || - (type.kind === "bytes" && (type.encode === "base64" || type.encode === "base64url")) - ) { + if (supportedPythonEncodings.get(pythonType)?.has(type.encode)) { return getSimpleTypeResult(context, { type: pythonType, encode: type.encode,