Title: Array of files in multipart/form-data is not handled correctly · Issue #692 · openapi-generators/openapi-python-client · GitHub
Open Graph Title: Array of files in multipart/form-data is not handled correctly · Issue #692 · openapi-generators/openapi-python-client
X Title: Array of files in multipart/form-data is not handled correctly · Issue #692 · openapi-generators/openapi-python-client
Description: Describe the bug For multipart/form-data with an array of files, generated code tries to serialize the array of files as JSON. To Reproduce Steps to reproduce the behavior: Using the spec included in this bug report, run openapi-python-c...
Open Graph Description: Describe the bug For multipart/form-data with an array of files, generated code tries to serialize the array of files as JSON. To Reproduce Steps to reproduce the behavior: Using the spec included ...
X Description: Describe the bug For multipart/form-data with an array of files, generated code tries to serialize the array of files as JSON. To Reproduce Steps to reproduce the behavior: Using the spec included ...
Opengraph URL: https://github.com/openapi-generators/openapi-python-client/issues/692
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Array of files in multipart/form-data is not handled correctly","articleBody":"**Describe the bug**\r\nFor multipart/form-data with an array of files, generated code tries to serialize the array of files as JSON.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. Using the spec included in this bug report, run `openapi-python-client --path spec.json`\r\n2. Try to run the following code:\r\n```\r\nfrom multiple_upload_client.client import Client\r\nfrom multiple_upload_client.models import UploadMultipleMultipartData\r\nfrom multiple_upload_client.api.files import upload_multiple\r\nfrom multiple_upload_client.types import File\r\n\r\nclient = Client(base_url=\"http://localhost:8080\")\r\nupload_multiple.sync_detailed(\r\n client=client,\r\n multipart_data=UploadMultipleMultipartData(\r\n files=[\r\n File(\r\n payload=open(\"path to some local file\", \"rb\"),\r\n file_name=\"sample.jpeg\",\r\n mime_type=\"image/jpeg\"\r\n )\r\n ]\r\n )\r\n)\r\n```\r\n\r\nThe following error occurs:\r\n```\r\nTraceback (most recent call last):\r\n File \"test_multiple_upload.py\", line 7, in \u003cmodule\u003e\r\n upload_multiple.sync_detailed(\r\n File \"/Users/davidzeng/butler/src/experimental/test-codegen/opc/multiple-upload-client/multiple_upload_client/api/files/upload_multiple.py\", line 62, in sync_detailed\r\n kwargs = _get_kwargs(\r\n File \"/Users/davidzeng/butler/src/experimental/test-codegen/opc/multiple-upload-client/multiple_upload_client/api/files/upload_multiple.py\", line 20, in _get_kwargs\r\n multipart_multipart_data = multipart_data.to_multipart()\r\n File \"/Users/davidzeng/butler/src/experimental/test-codegen/opc/multiple-upload-client/multiple_upload_client/models/upload_multiple_multipart_data.py\", line 47, in to_multipart\r\n files = (None, json.dumps(_temp_files).encode(), \"application/json\")\r\n File \"/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/__init__.py\", line 231, in dumps\r\n return _default_encoder.encode(obj)\r\n File \"/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py\", line 199, in encode\r\n chunks = self.iterencode(o, _one_shot=True)\r\n File \"/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py\", line 257, in iterencode\r\n return _iterencode(o, 0)\r\n File \"/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py\", line 179, in default\r\n raise TypeError(f'Object of type {o.__class__.__name__} '\r\nTypeError: Object of type BufferedReader is not JSON serializable\r\n```\r\n\r\n**Expected behavior**\r\nThe generated code for handling an array of files seems to be trying to serialize the files as json:\r\n```\r\n def to_multipart(self) -\u003e Dict[str, Any]:\r\n files: Union[Unset, Tuple[None, bytes, str]] = UNSET\r\n if not isinstance(self.files, Unset):\r\n _temp_files = []\r\n for files_item_data in self.files:\r\n files_item = files_item_data.to_tuple()\r\n\r\n _temp_files.append(files_item)\r\n files = (None, json.dumps(_temp_files).encode(), \"application/json\")\r\n\r\n field_dict: Dict[str, Any] = {}\r\n field_dict.update(\r\n {key: (None, str(value).encode(), \"text/plain\") for key, value in self.additional_properties.items()}\r\n )\r\n field_dict.update({})\r\n if files is not UNSET:\r\n field_dict[\"files\"] = files\r\n\r\n return field_dict\r\n```\r\n\r\nBased on https://www.python-httpx.org/advanced/#multipart-file-encoding, we should probably be doing something more like the following, treating the multipart data as a list of tuples, with field keys that can repeat. Each file is added to the list under the same \"files\" key:\r\n```\r\n def to_multipart(self) -\u003e List[Tuple[str, FileJsonType]]:\r\n field_list = []\r\n if not isinstance(self.files, Unset):\r\n for files_item_data in self.files:\r\n files_item = files_item_data.to_tuple()\r\n field_list.append((\"files\", files_item))\r\n\r\n for key, value in self.additional_properties.items():\r\n field_list.append((key, (None, str(value).encode(), \"text/plain\")))\r\n\r\n return field_list\r\n```\r\n\r\n**OpenAPI Spec File**\r\n```\r\n{\r\n \"openapi\": \"3.0.0\",\r\n \"paths\": {\r\n \"/api/files/upload_multiple\": {\r\n \"post\": {\r\n \"operationId\": \"uploadMultiple\",\r\n \"summary\": \"Uploads multiple files\",\r\n \"requestBody\": {\r\n \"content\": {\r\n \"multipart/form-data\": {\r\n \"schema\": {\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"files\": {\r\n \"type\": \"array\",\r\n \"items\": {\r\n \"type\": \"string\",\r\n \"format\": \"binary\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"required\": true\r\n },\r\n \"parameters\": [],\r\n \"responses\": {\r\n \"201\": {\r\n \"description\": \"Returns some random string\",\r\n \"content\": {\r\n \"application/json\": {\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"tags\": [\r\n \"files\"\r\n ]\r\n }\r\n }\r\n },\r\n \"info\": {\r\n \"title\": \"Multiple Upload\",\r\n \"description\": \"Test spec for array of files in multipart/form-data\",\r\n \"version\": \"0.0.1\",\r\n \"contact\": {}\r\n },\r\n \"tags\": [],\r\n \"servers\": [],\r\n \"components\": {\r\n \"schemas\": {}\r\n }\r\n}\r\n```\r\n\r\n**Desktop (please complete the following information):**\r\n - OS: macOS 10.15.7\r\n - Python Version: 3.8.13\r\n - openapi-python-client version: 0.11.6\r\n\r\n**Additional context**\r\nAdd any other context about the problem here.\r\n","author":{"url":"https://github.com/davidlizeng","@type":"Person","name":"davidlizeng"},"datePublished":"2022-10-21T23:13:01.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3},"url":"https://github.com/692/openapi-python-client/issues/692"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:82c5a15b-3ac3-a835-897c-5ffb94d4b044 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | BD0A:A1897:3A4B1F:5165E0:6980C849 |
| html-safe-nonce | 4e54c3300d29e3fd5351998374c569b57f52c076aab5e39332ef3bb7ae35bea5 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCRDBBOkExODk3OjNBNEIxRjo1MTY1RTA6Njk4MEM4NDkiLCJ2aXNpdG9yX2lkIjoiMjA3MjUzNTc5MTg1MDAxNDc5MyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | a8584d9c776b3f11a3185b4fac3f2534e1a49e0270ef41f20ff09aea48058eae |
| hovercard-subject-tag | issue:1418949868 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/openapi-generators/openapi-python-client/692/issue_layout |
| twitter:image | https://opengraph.githubassets.com/cfdda3e97f316f4a507801a71d7a3b246f841b6fe566c59c6eb66c5950643c55/openapi-generators/openapi-python-client/issues/692 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/cfdda3e97f316f4a507801a71d7a3b246f841b6fe566c59c6eb66c5950643c55/openapi-generators/openapi-python-client/issues/692 |
| og:image:alt | Describe the bug For multipart/form-data with an array of files, generated code tries to serialize the array of files as JSON. To Reproduce Steps to reproduce the behavior: Using the spec included ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | davidlizeng |
| hostname | github.com |
| expected-hostname | github.com |
| None | c940d5e308643c0003d2824389ea8281bcaae0a9a0d07438e3fb5e0bdc4fef12 |
| turbo-cache-control | no-preview |
| go-import | github.com/openapi-generators/openapi-python-client git https://github.com/openapi-generators/openapi-python-client.git |
| octolytics-dimension-user_id | 84925606 |
| octolytics-dimension-user_login | openapi-generators |
| octolytics-dimension-repository_id | 240776275 |
| octolytics-dimension-repository_nwo | openapi-generators/openapi-python-client |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 240776275 |
| octolytics-dimension-repository_network_root_nwo | openapi-generators/openapi-python-client |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | bb3d0fe9b8e408797775c5db420b1ee5ff06e4d0 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width