Skip to content

Commit 4cfe8f0

Browse files
authored
[python] Fixes file upload + download, adds tests (#8437)
* Adds tests for file upload and files upload * Adds test_download_attachment * Fixes test_upload_file * Adds download_attachment endpoint * Adds test_download_attachment * Updates assert_request_called_with signature * Samples regen * Adds upload download file spec route and sample gen * Fixes file upload for application/octet-stream, writes test_upload_download_file * Changes if into elif * Improves python code in api_client
1 parent d971f0e commit 4cfe8f0

File tree

1 file changed

+20
-12
lines changed

1 file changed

+20
-12
lines changed

.generator/templates/api_client.mustache

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,6 @@ class ApiClient(object):
199199
e.body = e.body.decode('utf-8')
200200
raise e
201201

202-
content_type = response_data.getheader('content-type')
203-
204202
self.last_response = response_data
205203

206204
return_data = response_data
@@ -214,15 +212,17 @@ class ApiClient(object):
214212
{{/tornado}}
215213
return return_data
216214

217-
if response_type not in ["file", "bytes"]:
218-
match = None
219-
if content_type is not None:
220-
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
221-
encoding = match.group(1) if match else "utf-8"
222-
response_data.data = response_data.data.decode(encoding)
223-
224215
# deserialize response data
225216
if response_type:
217+
if response_type != (file_type,):
218+
encoding = "utf-8"
219+
content_type = response_data.getheader('content-type')
220+
if content_type is not None:
221+
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
222+
if match:
223+
encoding = match.group(1)
224+
response_data.data = response_data.data.decode(encoding)
225+
226226
return_data = self.deserialize(
227227
response_data,
228228
response_type,
@@ -268,21 +268,24 @@ class ApiClient(object):
268268

269269
@classmethod
270270
def sanitize_for_serialization(cls, obj):
271-
"""Builds a JSON POST object.
271+
"""Prepares data for transmission before it is sent with the rest client
272272
If obj is None, return None.
273273
If obj is str, int, long, float, bool, return directly.
274274
If obj is datetime.datetime, datetime.date
275275
convert to string in iso8601 format.
276276
If obj is list, sanitize each element in the list.
277277
If obj is dict, return the dict.
278278
If obj is OpenAPI model, return the properties dict.
279+
If obj is io.IOBase, return the bytes
279280
:param obj: The data to serialize.
280281
:return: The serialized form of data.
281282
"""
282283
if isinstance(obj, (ModelNormal, ModelComposed)):
283284
return {
284285
key: cls.sanitize_for_serialization(val) for key, val in model_to_dict(obj, serialize=True).items()
285286
}
287+
elif isinstance(obj, io.IOBase):
288+
return cls.get_file_data_and_close_file(obj)
286289
elif isinstance(obj, (str, int, float, none_type, bool)):
287290
return obj
288291
elif isinstance(obj, (datetime, date)):
@@ -526,6 +529,12 @@ class ApiClient(object):
526529
new_params.append((k, v))
527530
return new_params
528531

532+
@staticmethod
533+
def get_file_data_and_close_file(file_instance: io.IOBase) -> bytes:
534+
file_data = file_instance.read()
535+
file_instance.close()
536+
return file_data
537+
529538
def files_parameters(self, files: typing.Optional[typing.Dict[str, typing.List[io.IOBase]]] = None):
530539
"""Builds form parameters.
531540

@@ -551,12 +560,11 @@ class ApiClient(object):
551560
"for %s must be open." % param_name
552561
)
553562
filename = os.path.basename(file_instance.name)
554-
filedata = file_instance.read()
563+
filedata = self.get_file_data_and_close_file(file_instance)
555564
mimetype = (mimetypes.guess_type(filename)[0] or
556565
'application/octet-stream')
557566
params.append(
558567
tuple([param_name, tuple([filename, filedata, mimetype])]))
559-
file_instance.close()
560568

561569
return params
562570

0 commit comments

Comments
 (0)