Skip to content

Commit 35d616c

Browse files
authored
Fix bug [python][client] generated python client code cannot POST object in multipart/form-data (#8075)
* encode object in json and add content-type:application/json for multipart/form-data fix issue #8068 * update samples by ./bin/generate-samples.sh * non-ascii chars supported in encoding object to json, and add "content-type:application/json; charset=utf-8" * update samples again, by ./bin/generate-samples.sh * update comment(docstring) in parameters_to_multipart according to the discussion in PR review. * fix default value in parameters_to_multipart function as described in PR review comment. * update samples again, by ./bin/generate-samples.sh
1 parent 751ffad commit 35d616c

File tree

5 files changed

+120
-0
lines changed

5 files changed

+120
-0
lines changed

modules/openapi-generator/src/main/resources/python/api_client.mustache

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import os
1010
import re
1111
import typing
1212
from urllib.parse import quote
13+
from urllib3.fields import RequestField
1314

1415
{{#tornado}}
1516
import tornado.gen
@@ -169,6 +170,9 @@ class ApiClient(object):
169170
post_params = self.parameters_to_tuples(post_params,
170171
collection_formats)
171172
post_params.extend(self.files_parameters(files))
173+
if header_params['Content-Type'].startswith("multipart"):
174+
post_params = self.parameters_to_multipart(post_params,
175+
(dict) )
172176

173177
# body
174178
if body:
@@ -243,6 +247,26 @@ class ApiClient(object):
243247
response_data.getheaders()))
244248
{{/tornado}}
245249

250+
def parameters_to_multipart(self, params, collection_types):
251+
"""Get parameters as list of tuples, formatting as json if value is collection_types
252+
253+
:param params: Parameters as list of two-tuples
254+
:param dict collection_types: Parameter collection types
255+
:return: Parameters as list of tuple or urllib3.fields.RequestField
256+
"""
257+
new_params = []
258+
if collection_types is None:
259+
collection_types = (dict)
260+
for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
261+
if isinstance(v, collection_types): # v is instance of collection_type, formatting as application/json
262+
v = json.dumps(v, ensure_ascii=False).encode("utf-8")
263+
field = RequestField(k, v)
264+
field.make_multipart(content_type="application/json; charset=utf-8")
265+
new_params.append(field)
266+
else:
267+
new_params.append((k, v))
268+
return new_params
269+
246270
@classmethod
247271
def sanitize_for_serialization(cls, obj):
248272
"""Builds a JSON POST object.

samples/client/petstore/python/petstore_api/api_client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import re
1919
import typing
2020
from urllib.parse import quote
21+
from urllib3.fields import RequestField
2122

2223

2324
from petstore_api import rest
@@ -171,6 +172,9 @@ def __call_api(
171172
post_params = self.parameters_to_tuples(post_params,
172173
collection_formats)
173174
post_params.extend(self.files_parameters(files))
175+
if header_params['Content-Type'].startswith("multipart"):
176+
post_params = self.parameters_to_multipart(post_params,
177+
(dict) )
174178

175179
# body
176180
if body:
@@ -231,6 +235,26 @@ def __call_api(
231235
return (return_data, response_data.status,
232236
response_data.getheaders())
233237

238+
def parameters_to_multipart(self, params, collection_types):
239+
"""Get parameters as list of tuples, formatting as json if value is collection_types
240+
241+
:param params: Parameters as list of two-tuples
242+
:param dict collection_types: Parameter collection types
243+
:return: Parameters as list of tuple or urllib3.fields.RequestField
244+
"""
245+
new_params = []
246+
if collection_types is None:
247+
collection_types = (dict)
248+
for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
249+
if isinstance(v, collection_types): # v is instance of collection_type, formatting as application/json
250+
v = json.dumps(v, ensure_ascii=False).encode("utf-8")
251+
field = RequestField(k, v)
252+
field.make_multipart(content_type="application/json; charset=utf-8")
253+
new_params.append(field)
254+
else:
255+
new_params.append((k, v))
256+
return new_params
257+
234258
@classmethod
235259
def sanitize_for_serialization(cls, obj):
236260
"""Builds a JSON POST object.

samples/openapi3/client/extensions/x-auth-id-alias/python/x_auth_id_alias/api_client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import re
1919
import typing
2020
from urllib.parse import quote
21+
from urllib3.fields import RequestField
2122

2223

2324
from x_auth_id_alias import rest
@@ -171,6 +172,9 @@ def __call_api(
171172
post_params = self.parameters_to_tuples(post_params,
172173
collection_formats)
173174
post_params.extend(self.files_parameters(files))
175+
if header_params['Content-Type'].startswith("multipart"):
176+
post_params = self.parameters_to_multipart(post_params,
177+
(dict) )
174178

175179
# body
176180
if body:
@@ -231,6 +235,26 @@ def __call_api(
231235
return (return_data, response_data.status,
232236
response_data.getheaders())
233237

238+
def parameters_to_multipart(self, params, collection_types):
239+
"""Get parameters as list of tuples, formatting as json if value is collection_types
240+
241+
:param params: Parameters as list of two-tuples
242+
:param dict collection_types: Parameter collection types
243+
:return: Parameters as list of tuple or urllib3.fields.RequestField
244+
"""
245+
new_params = []
246+
if collection_types is None:
247+
collection_types = (dict)
248+
for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
249+
if isinstance(v, collection_types): # v is instance of collection_type, formatting as application/json
250+
v = json.dumps(v, ensure_ascii=False).encode("utf-8")
251+
field = RequestField(k, v)
252+
field.make_multipart(content_type="application/json; charset=utf-8")
253+
new_params.append(field)
254+
else:
255+
new_params.append((k, v))
256+
return new_params
257+
234258
@classmethod
235259
def sanitize_for_serialization(cls, obj):
236260
"""Builds a JSON POST object.

samples/openapi3/client/features/dynamic-servers/python/dynamic_servers/api_client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import re
1919
import typing
2020
from urllib.parse import quote
21+
from urllib3.fields import RequestField
2122

2223

2324
from dynamic_servers import rest
@@ -171,6 +172,9 @@ def __call_api(
171172
post_params = self.parameters_to_tuples(post_params,
172173
collection_formats)
173174
post_params.extend(self.files_parameters(files))
175+
if header_params['Content-Type'].startswith("multipart"):
176+
post_params = self.parameters_to_multipart(post_params,
177+
(dict) )
174178

175179
# body
176180
if body:
@@ -231,6 +235,26 @@ def __call_api(
231235
return (return_data, response_data.status,
232236
response_data.getheaders())
233237

238+
def parameters_to_multipart(self, params, collection_types):
239+
"""Get parameters as list of tuples, formatting as json if value is collection_types
240+
241+
:param params: Parameters as list of two-tuples
242+
:param dict collection_types: Parameter collection types
243+
:return: Parameters as list of tuple or urllib3.fields.RequestField
244+
"""
245+
new_params = []
246+
if collection_types is None:
247+
collection_types = (dict)
248+
for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
249+
if isinstance(v, collection_types): # v is instance of collection_type, formatting as application/json
250+
v = json.dumps(v, ensure_ascii=False).encode("utf-8")
251+
field = RequestField(k, v)
252+
field.make_multipart(content_type="application/json; charset=utf-8")
253+
new_params.append(field)
254+
else:
255+
new_params.append((k, v))
256+
return new_params
257+
234258
@classmethod
235259
def sanitize_for_serialization(cls, obj):
236260
"""Builds a JSON POST object.

samples/openapi3/client/petstore/python/petstore_api/api_client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import re
1919
import typing
2020
from urllib.parse import quote
21+
from urllib3.fields import RequestField
2122

2223

2324
from petstore_api import rest
@@ -171,6 +172,9 @@ def __call_api(
171172
post_params = self.parameters_to_tuples(post_params,
172173
collection_formats)
173174
post_params.extend(self.files_parameters(files))
175+
if header_params['Content-Type'].startswith("multipart"):
176+
post_params = self.parameters_to_multipart(post_params,
177+
(dict) )
174178

175179
# body
176180
if body:
@@ -231,6 +235,26 @@ def __call_api(
231235
return (return_data, response_data.status,
232236
response_data.getheaders())
233237

238+
def parameters_to_multipart(self, params, collection_types):
239+
"""Get parameters as list of tuples, formatting as json if value is collection_types
240+
241+
:param params: Parameters as list of two-tuples
242+
:param dict collection_types: Parameter collection types
243+
:return: Parameters as list of tuple or urllib3.fields.RequestField
244+
"""
245+
new_params = []
246+
if collection_types is None:
247+
collection_types = (dict)
248+
for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
249+
if isinstance(v, collection_types): # v is instance of collection_type, formatting as application/json
250+
v = json.dumps(v, ensure_ascii=False).encode("utf-8")
251+
field = RequestField(k, v)
252+
field.make_multipart(content_type="application/json; charset=utf-8")
253+
new_params.append(field)
254+
else:
255+
new_params.append((k, v))
256+
return new_params
257+
234258
@classmethod
235259
def sanitize_for_serialization(cls, obj):
236260
"""Builds a JSON POST object.

0 commit comments

Comments
 (0)