Skip to content

Commit 08fabf4

Browse files
stainless-app[bot]stainless-bot
authored andcommitted
fix(client): always respect content-type multipart/form-data if provided (#419)
1 parent 677ce86 commit 08fabf4

File tree

1 file changed

+18
-2
lines changed

1 file changed

+18
-2
lines changed

src/finch/_base_client.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
HttpxSendArgs,
5959
AsyncTransport,
6060
RequestOptions,
61+
HttpxRequestFiles,
6162
ModelBuilderProtocol,
6263
)
6364
from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
@@ -460,6 +461,7 @@ def _build_request(
460461
headers = self._build_headers(options)
461462
params = _merge_mappings(self.default_query, options.params)
462463
content_type = headers.get("Content-Type")
464+
files = options.files
463465

464466
# If the given Content-Type header is multipart/form-data then it
465467
# has to be removed so that httpx can generate the header with
@@ -473,14 +475,23 @@ def _build_request(
473475
headers.pop("Content-Type")
474476

475477
# As we are now sending multipart/form-data instead of application/json
476-
# we need to tell httpx to use it, https://www.python-httpx.org/advanced/#multipart-file-encoding
478+
# we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding
477479
if json_data:
478480
if not is_dict(json_data):
479481
raise TypeError(
480482
f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead."
481483
)
482484
kwargs["data"] = self._serialize_multipartform(json_data)
483485

486+
# httpx determines whether or not to send a "multipart/form-data"
487+
# request based on the truthiness of the "files" argument.
488+
# This gets around that issue by generating a dict value that
489+
# evaluates to true.
490+
#
491+
# https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186
492+
if not files:
493+
files = cast(HttpxRequestFiles, ForceMultipartDict())
494+
484495
# TODO: report this error to httpx
485496
return self._client.build_request( # pyright: ignore[reportUnknownMemberType]
486497
headers=headers,
@@ -493,7 +504,7 @@ def _build_request(
493504
# https://github.com/microsoft/pyright/issues/3526#event-6715453066
494505
params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None,
495506
json=json_data,
496-
files=options.files,
507+
files=files,
497508
**kwargs,
498509
)
499510

@@ -1890,6 +1901,11 @@ def make_request_options(
18901901
return options
18911902

18921903

1904+
class ForceMultipartDict(Dict[str, None]):
1905+
def __bool__(self) -> bool:
1906+
return True
1907+
1908+
18931909
class OtherPlatform:
18941910
def __init__(self, name: str) -> None:
18951911
self.name = name

0 commit comments

Comments
 (0)