@@ -158,7 +158,11 @@ def transcode_request(
158158 use_integers_for_enums = rest_numeric_enums ,
159159 )
160160
161+ # If required_fields_default_values is provided, we merge default values for missing
162+ # required fields into the query parameters. However, we must exclude any fields
163+ # that are already bound to the URI path or the request body for the matched HTTP option.
161164 if required_fields_default_values :
165+ # 1. Identify which HTTP option matched the transcoded request by comparing method and URI.
162166 matched_option = None
163167 for option in http_options :
164168 if (
@@ -171,6 +175,8 @@ def transcode_request(
171175 matched_option = option
172176 break
173177
178+ # 2. Determine which fields are bound to the path or body.
179+ # If the body is '*', all fields are bound to the body, so bound_fields is None.
174180 bound_fields : Optional [Set [str ]] = set ()
175181 if matched_option :
176182 body_param = matched_option .get ("body" )
@@ -179,11 +185,17 @@ def transcode_request(
179185 else :
180186 assert bound_fields is not None
181187 uri_template = matched_option .get ("uri" , "" )
188+ # Extract the top-level field names for variables in the URI path.
189+ # E.g., for URI "/v1/{name}" we extract "name".
190+ # For nested path variables like "{options.deprecated}", we split on "."
191+ # and extract the top-level field "options", because required_fields_default_values
192+ # only maps top-level request field names to their default values.
182193 for m in path_template ._VARIABLE_RE .finditer (uri_template ):
183194 bound_fields .add (m .group ("name" ).split ("." )[0 ])
184195 if body_param :
185196 bound_fields .add (body_param .split ("." )[0 ])
186197
198+ # 3. Only merge default values for fields that are not bound to the path or body.
187199 if bound_fields is not None :
188200 for k , v in required_fields_default_values .items ():
189201 if k in bound_fields :
0 commit comments