| 506 | return SSEDecoder() |
| 507 | |
| 508 | def _build_request( |
| 509 | self, |
| 510 | options: FinalRequestOptions, |
| 511 | *, |
| 512 | retries_taken: int = 0, |
| 513 | ) -> httpx.Request: |
| 514 | if log.isEnabledFor(logging.DEBUG): |
| 515 | log.debug( |
| 516 | "Request options: %s", |
| 517 | model_dump( |
| 518 | options, |
| 519 | exclude_unset=True, |
| 520 | # Pydantic v1 can't dump every type we support in content, so we exclude it for now. |
| 521 | exclude={ |
| 522 | "content", |
| 523 | } |
| 524 | if PYDANTIC_V1 |
| 525 | else {}, |
| 526 | ), |
| 527 | ) |
| 528 | kwargs: dict[str, Any] = {} |
| 529 | |
| 530 | json_data = options.json_data |
| 531 | if options.extra_json is not None: |
| 532 | if json_data is None: |
| 533 | json_data = cast(Body, options.extra_json) |
| 534 | elif is_mapping(json_data): |
| 535 | json_data = _merge_mappings(json_data, options.extra_json) |
| 536 | else: |
| 537 | raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") |
| 538 | |
| 539 | headers = self._build_headers(options, retries_taken=retries_taken) |
| 540 | params = _merge_mappings(self.default_query, options.params) |
| 541 | content_type = headers.get("Content-Type") |
| 542 | files = options.files |
| 543 | |
| 544 | # If the given Content-Type header is multipart/form-data then it |
| 545 | # has to be removed so that httpx can generate the header with |
| 546 | # additional information for us as it has to be in this form |
| 547 | # for the server to be able to correctly parse the request: |
| 548 | # multipart/form-data; boundary=---abc-- |
| 549 | if content_type is not None and content_type.startswith("multipart/form-data"): |
| 550 | if "boundary" not in content_type: |
| 551 | # only remove the header if the boundary hasn't been explicitly set |
| 552 | # as the caller doesn't want httpx to come up with their own boundary |
| 553 | headers.pop("Content-Type") |
| 554 | |
| 555 | # As we are now sending multipart/form-data instead of application/json |
| 556 | # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding |
| 557 | if json_data: |
| 558 | if not is_dict(json_data): |
| 559 | raise TypeError( |
| 560 | f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead." |
| 561 | ) |
| 562 | kwargs["data"] = self._serialize_multipartform(json_data) |
| 563 | |
| 564 | # httpx determines whether or not to send a "multipart/form-data" |
| 565 | # request based on the truthiness of the "files" argument. |