[python] fix: omit content-type header when optional body is absent#11272
[python] fix: omit content-type header when optional body is absent#11272msyyc wants to merge 1 commit into
Conversation
commit: |
|
All changed packages have been documented.
Show changes
|
There was a problem hiding this comment.
Pull request overview
Fixes the TypeSpec Python HTTP client generator so that generated request builders omit the content-type header when the request body is optional and absent, preventing _SERIALIZER.header(..., None, ...) from raising ValueError: No value for given attribute (issue #11253).
Changes:
- Thread
is_body_optionalinto request-builder kwarg popping and header serialization socontent_typebecomesOptional[str]with aNonedefault and the header is conditionally emitted. - Update request-builder serialization to derive body optionality from the modeled body parameter (including
dpgscenarios where the body isn’t in the request-builder signature). - Add unit regression tests and a Chronus changelog entry.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/http-client-python/generator/pygen/codegen/serializers/parameter_serializer.py | Adds is_body_optional handling to treat content-type as nullable/guarded when body is optional. |
| packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py | Passes body optionality through to request-builder kwarg/header serialization. |
| packages/http-client-python/tests/unit/test_content_type_optional_body.py | Adds regression unit tests covering guarded header emission and optionalized content_type kwarg. |
| .chronus/changes/http-client-python_fix-optional-body-content-type-2026-7-16-0-0-0.md | Records the generator fix in the changelog. |
|
You can try these changes here
|
For #11253
Problem
For an operation with an optional body whose content-type is modeled as required/constant (a single specific media type, e.g. azure-batch's
application/json; odata=minimalmetadata), the generated client crashes when called without a body:The operation layer correctly computed
content_type = Nonewhen no body was passed, but the generated request builder declaredcontent_type: str = kwargs.pop("content_type")(required) and serialized the header unconditionally, so_SERIALIZER.header("content_type", None, "str")raised.The asymmetry was the defect: the operation layer knew the body was optional, but the request-builder layer did not.
Fix
Thread body-optionality into the request-builder layer so a
Nonecontent-type is omitted instead of serialized.parameter_serializer.pyserialize_query_headernow acceptsis_body_optionaland guards the content-type header withif content_type is not None:when the body is optional.pop_kwargs_from_signatureaccepts an explicitis_body_optionaland declares the content-type kwarg asOptional[str] = kwargs.pop("content_type", ...None)even when the param is otherwise required.builder_serializer.pypop_kwargs_from_signatureandserialize_headerspassis_body_optional(derived frombody_parameter.optional, reliable even indpgmode where the request-builder body isn't in the signature).Operation-layer behavior is unchanged (its
content_type = content_type if body else Nonereassignment is not emitted in the request builder).Generated code (after)
Verification
content_type: Optional[str]and guards the header.tests/unit/test_content_type_optional_body.py(4 tests); full unit suite passes.Code Diff
No code diff caused by this PR