From 210761931f0d26a1db21aa576ca057ee351e375e Mon Sep 17 00:00:00 2001 From: Libba Lawrence Date: Wed, 10 Jun 2026 14:21:46 -0700 Subject: [PATCH] fix(http-client-python): construct paging JSON body outside prepare_request For paging operations with a flattened JSON model body, the body construction (if body is _Unset: ...) was emitted inside the prepare_request closure. Assigning ody there made it a function-local, so reading if body is _Unset: raised UnboundLocalError on every page fetch. Move the construction out of the closure and before the body is serialized into the request content. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../fix-paging-unset-body-placement-2026-06-10.md | 7 +++++++ .../pygen/codegen/serializers/builder_serializer.py | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 .chronus/changes/fix-paging-unset-body-placement-2026-06-10.md diff --git a/.chronus/changes/fix-paging-unset-body-placement-2026-06-10.md b/.chronus/changes/fix-paging-unset-body-placement-2026-06-10.md new file mode 100644 index 00000000000..a86f2075fa3 --- /dev/null +++ b/.chronus/changes/fix-paging-unset-body-placement-2026-06-10.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-client-python" +--- + +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. diff --git a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py index 5dcf94e32b4..c615baf827f 100644 --- a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py +++ b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py @@ -931,7 +931,8 @@ def _call_request_builder_helper( if builder.parameters.has_body and builder.parameters.body_parameter.flattened: # serialize flattened body before passing to request builder as well retval.extend(_serialize_flattened_body(builder.parameters.body_parameter)) - if is_json_model_type(builder.parameters): + if is_json_model_type(builder.parameters) and not is_paging: + # For paging, we put the json model body outside `prepare_request` retval.extend(_serialize_json_model_body(builder.parameters.body_parameter, builder.parameters.parameters)) if builder.has_form_data_body: retval.extend(self._create_body_parameter(builder)) @@ -1369,7 +1370,13 @@ def call_next_link_request_builder(self, builder: PagingOperationType) -> list[s return retval def _prepare_request_callback(self, builder: PagingOperationType) -> list[str]: - retval = self._initialize_overloads(builder) + retval: list[str] = [] + # The json model body must be constructed before `_initialize_overloads` + # serializes it into the request content, and outside `prepare_request` so + # the closure doesn't treat `body` as an unbound local. + if is_json_model_type(builder.parameters): + retval.extend(_serialize_json_model_body(builder.parameters.body_parameter, builder.parameters.parameters)) + retval.extend(self._initialize_overloads(builder)) if builder.has_continuation_token: retval.append(f"def prepare_request({builder.next_variable_name}=None):") retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])