diff --git a/modules/openapi-json-schema-generator/src/main/resources/python/api_client.handlebars b/modules/openapi-json-schema-generator/src/main/resources/python/api_client.handlebars index 81426853056..f1514924c48 100644 --- a/modules/openapi-json-schema-generator/src/main/resources/python/api_client.handlebars +++ b/modules/openapi-json-schema-generator/src/main/resources/python/api_client.handlebars @@ -1399,24 +1399,24 @@ class RequestBody(StyleFormSerializer, JSONDetector): def __multipart_json_item(self, key: str, value: Schema) -> RequestField: json_value = self.__json_encoder.default(value) - return RequestField(name=key, data=json.dumps(json_value), headers={'Content-Type': 'application/json'}) + request_field = RequestField(name=key, data=json.dumps(json_value)) + request_field.make_multipart(content_type='application/json') + return request_field def __multipart_form_item(self, key: str, value: Schema) -> RequestField: if isinstance(value, str): - return RequestField(name=key, data=str(value), headers={'Content-Type': 'text/plain'}) + request_field = RequestField(name=key, data=str(value)) + request_field.make_multipart(content_type='text/plain') elif isinstance(value, bytes): - return RequestField(name=key, data=value, headers={'Content-Type': 'application/octet-stream'}) + request_field = RequestField(name=key, data=value) + request_field.make_multipart(content_type='application/octet-stream') elif isinstance(value, FileIO): - request_field = RequestField( - name=key, - data=value.read(), - filename=os.path.basename(value.name), - headers={'Content-Type': 'application/octet-stream'} - ) + # TODO use content.encoding to limit allowed content types if they are present + request_field = RequestField.from_tuples(key, (os.path.basename(value.name), value.read())) value.close() - return request_field else: - return self.__multipart_json_item(key=key, value=value) + request_field = self.__multipart_json_item(key=key, value=value) + return request_field def __serialize_multipart_form_data( self, in_data: Schema diff --git a/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/api_client.py b/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/api_client.py index 6fa884fc7d8..3985bb0565b 100644 --- a/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/api_client.py +++ b/samples/openapi3/client/3_0_3_unit_test/python/unit_test_api/api_client.py @@ -1389,24 +1389,24 @@ def __serialize_text_plain(in_data: typing.Any) -> typing.Dict[str, str]: def __multipart_json_item(self, key: str, value: Schema) -> RequestField: json_value = self.__json_encoder.default(value) - return RequestField(name=key, data=json.dumps(json_value), headers={'Content-Type': 'application/json'}) + request_field = RequestField(name=key, data=json.dumps(json_value)) + request_field.make_multipart(content_type='application/json') + return request_field def __multipart_form_item(self, key: str, value: Schema) -> RequestField: if isinstance(value, str): - return RequestField(name=key, data=str(value), headers={'Content-Type': 'text/plain'}) + request_field = RequestField(name=key, data=str(value)) + request_field.make_multipart(content_type='text/plain') elif isinstance(value, bytes): - return RequestField(name=key, data=value, headers={'Content-Type': 'application/octet-stream'}) + request_field = RequestField(name=key, data=value) + request_field.make_multipart(content_type='application/octet-stream') elif isinstance(value, FileIO): - request_field = RequestField( - name=key, - data=value.read(), - filename=os.path.basename(value.name), - headers={'Content-Type': 'application/octet-stream'} - ) + # TODO use content.encoding to limit allowed content types if they are present + request_field = RequestField.from_tuples(key, (os.path.basename(value.name), value.read())) value.close() - return request_field else: - return self.__multipart_json_item(key=key, value=value) + request_field = self.__multipart_json_item(key=key, value=value) + return request_field def __serialize_multipart_form_data( self, in_data: Schema diff --git a/samples/openapi3/client/features/nonCompliantUseDiscriminatorIfCompositionFails/python/this_package/api_client.py b/samples/openapi3/client/features/nonCompliantUseDiscriminatorIfCompositionFails/python/this_package/api_client.py index 048ae4ed1ba..bdab1907d48 100644 --- a/samples/openapi3/client/features/nonCompliantUseDiscriminatorIfCompositionFails/python/this_package/api_client.py +++ b/samples/openapi3/client/features/nonCompliantUseDiscriminatorIfCompositionFails/python/this_package/api_client.py @@ -1389,24 +1389,24 @@ def __serialize_text_plain(in_data: typing.Any) -> typing.Dict[str, str]: def __multipart_json_item(self, key: str, value: Schema) -> RequestField: json_value = self.__json_encoder.default(value) - return RequestField(name=key, data=json.dumps(json_value), headers={'Content-Type': 'application/json'}) + request_field = RequestField(name=key, data=json.dumps(json_value)) + request_field.make_multipart(content_type='application/json') + return request_field def __multipart_form_item(self, key: str, value: Schema) -> RequestField: if isinstance(value, str): - return RequestField(name=key, data=str(value), headers={'Content-Type': 'text/plain'}) + request_field = RequestField(name=key, data=str(value)) + request_field.make_multipart(content_type='text/plain') elif isinstance(value, bytes): - return RequestField(name=key, data=value, headers={'Content-Type': 'application/octet-stream'}) + request_field = RequestField(name=key, data=value) + request_field.make_multipart(content_type='application/octet-stream') elif isinstance(value, FileIO): - request_field = RequestField( - name=key, - data=value.read(), - filename=os.path.basename(value.name), - headers={'Content-Type': 'application/octet-stream'} - ) + # TODO use content.encoding to limit allowed content types if they are present + request_field = RequestField.from_tuples(key, (os.path.basename(value.name), value.read())) value.close() - return request_field else: - return self.__multipart_json_item(key=key, value=value) + request_field = self.__multipart_json_item(key=key, value=value) + return request_field def __serialize_multipart_form_data( self, in_data: Schema diff --git a/samples/openapi3/client/petstore/python/petstore_api/api_client.py b/samples/openapi3/client/petstore/python/petstore_api/api_client.py index 9ee9ff13f68..b4a583829a3 100644 --- a/samples/openapi3/client/petstore/python/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python/petstore_api/api_client.py @@ -1398,24 +1398,24 @@ def __serialize_text_plain(in_data: typing.Any) -> typing.Dict[str, str]: def __multipart_json_item(self, key: str, value: Schema) -> RequestField: json_value = self.__json_encoder.default(value) - return RequestField(name=key, data=json.dumps(json_value), headers={'Content-Type': 'application/json'}) + request_field = RequestField(name=key, data=json.dumps(json_value)) + request_field.make_multipart(content_type='application/json') + return request_field def __multipart_form_item(self, key: str, value: Schema) -> RequestField: if isinstance(value, str): - return RequestField(name=key, data=str(value), headers={'Content-Type': 'text/plain'}) + request_field = RequestField(name=key, data=str(value)) + request_field.make_multipart(content_type='text/plain') elif isinstance(value, bytes): - return RequestField(name=key, data=value, headers={'Content-Type': 'application/octet-stream'}) + request_field = RequestField(name=key, data=value) + request_field.make_multipart(content_type='application/octet-stream') elif isinstance(value, FileIO): - request_field = RequestField( - name=key, - data=value.read(), - filename=os.path.basename(value.name), - headers={'Content-Type': 'application/octet-stream'} - ) + # TODO use content.encoding to limit allowed content types if they are present + request_field = RequestField.from_tuples(key, (os.path.basename(value.name), value.read())) value.close() - return request_field else: - return self.__multipart_json_item(key=key, value=value) + request_field = self.__multipart_json_item(key=key, value=value) + return request_field def __serialize_multipart_form_data( self, in_data: Schema diff --git a/samples/openapi3/client/petstore/python/tests_manual/test_fake_api.py b/samples/openapi3/client/petstore/python/tests_manual/test_fake_api.py index 7ce4a60e8f7..cd990c9bc39 100644 --- a/samples/openapi3/client/petstore/python/tests_manual/test_fake_api.py +++ b/samples/openapi3/client/petstore/python/tests_manual/test_fake_api.py @@ -468,7 +468,11 @@ def test_upload_file(self): name='file', data=file_bytes, filename=file_name, - headers={'Content-Type': 'application/octet-stream'} + headers={ + 'Content-Location': None, + 'Content-Type': 'image/png', + "Content-Disposition": "form-data; name=\"file\"; filename=\"1px_pic1.png\"" + } ), ), content_type='multipart/form-data' @@ -492,7 +496,11 @@ def test_upload_file(self): api_client.RequestField( name='file', data=file_bytes, - headers={'Content-Type': 'application/octet-stream'} + headers={ + 'Content-Type': 'application/octet-stream', + "Content-Disposition": "form-data; name=\"file\"", + "Content-Location": None + } ), ), content_type='multipart/form-data' @@ -547,13 +555,22 @@ def test_upload_files(self): name='files', data=file_bytes, filename=file_name, - headers={'Content-Type': 'application/octet-stream'} + headers={ + 'Content-Type': 'image/png', + "Content-Disposition": "form-data; name=\"files\"; filename=\"1px_pic1.png\"", + "Content-Location": None + } ), api_client.RequestField( name='files', data=file_bytes, filename=file_name, - headers={'Content-Type': 'application/octet-stream'} + headers={ + 'Content-Type': 'image/png', + "Content-Disposition": "form-data; name=\"files\"; filename=\"1px_pic1.png\"", + "Content-Location": None + + } ), ), content_type='multipart/form-data' @@ -578,12 +595,20 @@ def test_upload_files(self): api_client.RequestField( name='files', data=file_bytes, - headers={'Content-Type': 'application/octet-stream'} + headers={ + 'Content-Type': 'application/octet-stream', + "Content-Disposition": "form-data; name=\"files\"", + "Content-Location": None + } ), api_client.RequestField( name='files', data=file_bytes, - headers={'Content-Type': 'application/octet-stream'} + headers={ + 'Content-Type': 'application/octet-stream', + "Content-Disposition": "form-data; name=\"files\"", + "Content-Location": None + } ), ), content_type='multipart/form-data' @@ -656,11 +681,15 @@ def test_inline_composition(self, mock_request): accept_content_type=content_type, content_type=content_type, fields=( - api_client.RequestField( - name='someProp', - data=single_char_str, - headers={'Content-Type': 'text/plain'} - ), + api_client.RequestField( + name='someProp', + data=single_char_str, + headers={ + 'Content-Type': 'text/plain', + "Content-Disposition": "form-data; name=\"someProp\"", + "Content-Location": None + } + ), ), ) self.assertEqual(api_response.body, {'someProp': single_char_str}) diff --git a/samples/openapi3/client/petstore/python/tests_manual/test_request_body.py b/samples/openapi3/client/petstore/python/tests_manual/test_request_body.py index 000e04f90a1..14339c2e230 100644 --- a/samples/openapi3/client/petstore/python/tests_manual/test_request_body.py +++ b/samples/openapi3/client/petstore/python/tests_manual/test_request_body.py @@ -71,21 +71,53 @@ def test_content_multipart_form_data_serialization(self): dict( fields=( api_client.RequestField( - name='some_null', data='null', headers={'Content-Type': 'application/json'}), + name='some_null', data='null', headers={ + 'Content-Type': 'application/json', + "Content-Disposition": "form-data; name=\"some_null\"", + "Content-Location": None + }), api_client.RequestField( - name='some_bool', data='true', headers={'Content-Type': 'application/json'}), + name='some_bool', data='true', headers={ + 'Content-Type': 'application/json', + "Content-Disposition": "form-data; name=\"some_bool\"", + "Content-Location": None + }), api_client.RequestField( - name='some_str', data='a', headers={'Content-Type': 'text/plain'}), + name='some_str', data='a', headers={ + 'Content-Type': 'text/plain', + "Content-Disposition": "form-data; name=\"some_str\"", + "Content-Location": None + }), api_client.RequestField( - name='some_int', data='1', headers={'Content-Type': 'application/json'}), + name='some_int', data='1', headers={ + 'Content-Type': 'application/json', + "Content-Disposition": "form-data; name=\"some_int\"", + "Content-Location": None + }), api_client.RequestField( - name='some_float', data='3.14', headers={'Content-Type': 'application/json'}), + name='some_float', data='3.14', headers={ + 'Content-Type': 'application/json', + "Content-Disposition": "form-data; name=\"some_float\"", + "Content-Location": None + }), api_client.RequestField( - name='some_list', data='[]', headers={'Content-Type': 'application/json'}), + name='some_list', data='[]', headers={ + 'Content-Type': 'application/json', + "Content-Disposition": "form-data; name=\"some_list\"", + "Content-Location": None + }), api_client.RequestField( - name='some_dict', data='{}', headers={'Content-Type': 'application/json'}), + name='some_dict', data='{}', headers={ + 'Content-Type': 'application/json', + "Content-Disposition": "form-data; name=\"some_dict\"", + "Content-Location": None + }), api_client.RequestField( - name='some_bytes', data=b'abc', headers={'Content-Type': 'application/octet-stream'}) + name='some_bytes', data=b'abc', headers={ + 'Content-Type': 'application/octet-stream', + "Content-Disposition": "form-data; name=\"some_bytes\"", + "Content-Location": None + }) ) ) )