diff --git a/.chronus/changes/python-nightly-fix-2026-1-6-9-19-9.md b/.chronus/changes/python-nightly-fix-2026-1-6-9-19-9.md new file mode 100644 index 00000000000..271dc9d3c44 --- /dev/null +++ b/.chronus/changes/python-nightly-fix-2026-1-6-9-19-9.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-client-python" +--- + +Fall back "Http.File" to "bytes" to avoid generation failure \ No newline at end of file diff --git a/packages/http-client-python/emitter/src/http.ts b/packages/http-client-python/emitter/src/http.ts index 99184365d16..df1ee4702c3 100644 --- a/packages/http-client-python/emitter/src/http.ts +++ b/packages/http-client-python/emitter/src/http.ts @@ -480,6 +480,7 @@ function emitHttpHeaderParameter( parameter: SdkHeaderParameter, method: SdkServiceMethod, serviceApiVersions: string[], + bodyParam?: SdkBodyParameter, ): Record { const base = emitParamBase(context, parameter, method, serviceApiVersions); const [delimiter, explode] = getDelimiterAndExplode(parameter); @@ -489,6 +490,16 @@ function emitHttpHeaderParameter( if (!clientDefaultValue && parameter.type.kind === "constant") { clientDefaultValue = parameter.type.value; } + // if still no default value, try to derive from body parameter's content types + if (!clientDefaultValue && bodyParam) { + const fileContentTypes = getHttpFileContentTypes(bodyParam); + const defaultContentType = fileContentTypes + ? fileContentTypes[0] + : bodyParam.defaultContentType; + if (defaultContentType) { + clientDefaultValue = defaultContentType; + } + } base.type = KnownTypes.string; } return { @@ -571,7 +582,15 @@ function emitHttpParameters( for (const parameter of httpParameters) { switch (parameter.kind) { case "header": - parameters.push(emitHttpHeaderParameter(context, parameter, method, serviceApiVersions)); + parameters.push( + emitHttpHeaderParameter( + context, + parameter, + method, + serviceApiVersions, + operation.bodyParam, + ), + ); break; case "query": parameters.push( @@ -587,21 +606,40 @@ function emitHttpParameters( return parameters; } +function isHttpFileType( + type: { kind: string; crossLanguageDefinitionId?: string } | undefined, +): boolean { + return type?.kind === "model" && type?.crossLanguageDefinitionId === "TypeSpec.Http.File"; +} + +function getHttpFileContentTypes(bodyParam: SdkBodyParameter): string[] | undefined { + if (bodyParam.type.kind === "model" && isHttpFileType(bodyParam.type)) { + const contentTypeProp = bodyParam.type.properties.find((p) => p.name === "contentType"); + if (contentTypeProp && contentTypeProp.type.kind === "constant" && contentTypeProp.type.value) { + return [String(contentTypeProp.type.value)]; + } + } + return undefined; +} + function emitHttpBodyParameter( context: PythonSdkContext, bodyParam?: SdkBodyParameter, serviceApiVersions: string[] = [], ): Record | undefined { if (bodyParam === undefined) return undefined; + const fileContentTypes = getHttpFileContentTypes(bodyParam); + const contentTypes = fileContentTypes ?? bodyParam.contentTypes; + const defaultContentType = fileContentTypes ? fileContentTypes[0] : bodyParam.defaultContentType; return { ...emitParamBase(context, bodyParam, undefined, serviceApiVersions), - contentTypes: bodyParam.contentTypes, + contentTypes, location: bodyParam.kind, clientName: bodyParam.isGeneratedName ? "body" : camelToSnakeCase(bodyParam.name), wireName: bodyParam.isGeneratedName ? "body" : bodyParam.name, implementation: getImplementation(context, bodyParam), clientDefaultValue: bodyParam.clientDefaultValue, - defaultContentType: bodyParam.defaultContentType, + defaultContentType, }; } @@ -637,8 +675,13 @@ function emitHttpResponse( type["referredByOperationType"] |= referredBy; } + const httpFile = isHttpFileType(response.type); + const headers = response.headers + .filter((x) => !httpFile || x.serializedName) + .map((x) => emitHttpResponseHeader(context, x)); + return { - headers: response.headers.map((x) => emitHttpResponseHeader(context, x)), + headers, statusCodes: typeof statusCodes === "object" ? [[(statusCodes as HttpStatusCodeRange).start, (statusCodes as HttpStatusCodeRange).end]] diff --git a/packages/http-client-python/emitter/src/types.ts b/packages/http-client-python/emitter/src/types.ts index 4bffbdbb2c6..81ed41428e1 100644 --- a/packages/http-client-python/emitter/src/types.ts +++ b/packages/http-client-python/emitter/src/types.ts @@ -260,6 +260,9 @@ function emitModel(context: PythonSdkContext, type: SdkModelType): Record | Record | Record