New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Multi-part upload] TypeError: Object of type BytesIO is not JSON serializable #771
Comments
I had a similar problem, but with a endpoint for downloads. Have a look at the OpenAPI file from which you generated the client. In my case it looks like this: "/api/Data/.../DownloadData": {
"get": {
"responses": {
"200": {
"description": "Success",
"headers": { "..." },
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
} The problem occurs, if you define the MIME type as something else than Even if you up/download Json data, the mime type of the endpoint should be Cheers Edit:: "/api/Data/ ... /UploadData": {
"post": {
"requestBody": {
"description": "File to upload",
"content": {
"multipart/form-data": {
"schema": {
"required": [
"SomeData"
],
"type": "object",
"properties": {
"SomeData": {
"type": "string",
"format": "binary"
}
}
}
}
}
} |
I am having the same issue for an API body that receives an array of files (binary objects). The relevant schema looks like this:
The code generated correctly parses main_image, but assumes the list of files should, somehow, be json encoded: def to_multipart(self) -> Dict[str, Any]:
productmain_image: Union[Unset, FileJsonType] = UNSET
if not isinstance(self.productmain_image, Unset):
productmain_image = self.productmain_image.to_tuple()
productappend_files: Union[Unset, Tuple[None, bytes, str]] = UNSET
if not isinstance(self.productappend_files, Unset):
_temp_productappend_files = []
for productappend_files_item_data in self.productappend_files:
productappend_files_item = productappend_files_item_data.to_tuple()
_temp_productappend_files.append(productappend_files_item)
productappend_files = (None, json.dumps(_temp_productappend_files).encode(), "application/json")
field_dict: Dict[str, Any] = {}
field_dict.update(
{key: (None, str(value).encode(), "text/plain") for key, value in self.additional_properties.items()}
)
field_dict.update({})
if productmain_image is not UNSET:
field_dict["product[main_image]"] = productmain_image
if productappend_files is not UNSET:
field_dict["product[append_files][]"] = productappend_files
return field_dict I use the generated client code to build the input: input_dict = {}
if "main_image" in attachments_paths:
input_dict["product[main_image]"] = self._build_file(
attachments_paths.pop("main_image"))
input_dict["product[files][]"] = [
self._build_file(path) for path in attachments_paths.values()
]
media_creation_data = ProductMediaCreationInput(
productmain_image=input_dict["product[main_image]"],
productfiles=input_dict["product[files][]"]
)
...
def _build_file(self, file_path: str) -> File:
return File(
payload=BytesIO(open(file_path, 'rb').read()),
file_name=file_path.split('/')[-1],
mime_type=magic.Magic(mime=True).from_file(file_path),
) But when I call the API client: post_api_v1_products_product_id_media.sync_detailed(
client=self.client, product_id=product_id, multipart_data=media_creation_data) it fails with "TypeError: Object of type BytesIO is not JSON serializable" |
I was able to patch my generated code to look like this, and now it works fine: def to_multipart(self) -> list[Tuple[str, FileJsonType]]:
productmain_image: Union[Unset, FileJsonType] = UNSET
if not isinstance(self.productmain_image, Unset):
productmain_image = self.productmain_image.to_tuple()
productappend_files: Union[Unset, list[FileJsonType]] = UNSET
if not isinstance(self.productappend_files, Unset):
_temp_productappend_files = []
for productappend_files_item_data in self.productappend_files:
productappend_files_item = productappend_files_item_data.to_tuple()
_temp_productappend_files.append(productappend_files_item)
productappend_files = _temp_productappend_files
field_dict: list[Tuple[str, FileJsonType]] = []
for key, value in self.additional_properties.items():
field_dict.append((key, (None, str(value).encode(), "text/plain")))
if productmain_image is not UNSET:
field_dict.append(("product[main_image]", productmain_image))
if productappend_files is not UNSET:
for productappend_files_item in productappend_files:
field_dict.append(
("product[append_files][]", productappend_files_item))
return field_dict It feels reasonable that a multipart request with multiple files on the same key (an array of files) would not be json encoded and would require to be handled as a list of tuples (as documented by httpx). It would be great if the code generation logic used this (or something closer) to fix the issue. |
I have a generated client code for FastAPI multi-file upload endpoint which I'm using like this:
I get an error:
Generated
File
class:Looks like generated code tries to call json.dumps() on tuple representation of File, which has BinaryIO field, this causes the exception.
What am I doing wrong?
The text was updated successfully, but these errors were encountered: