From 5e8ad7a0d425de0df7c00c9a864f00dd992856bb Mon Sep 17 00:00:00 2001 From: Michael Harbarth Date: Tue, 13 May 2025 09:39:38 +0200 Subject: [PATCH 1/6] chore: Reimplement functionality based on the latest main --- end_to_end_tests/baseline_openapi_3.0.json | 49 +++++++++++ end_to_end_tests/baseline_openapi_3.1.yaml | 49 +++++++++++ .../my_test_api_client/api/tests/__init__.py | 8 ++ .../my_test_api_client/models/__init__.py | 2 + .../my_test_api_client/models/a_model.py | 1 + .../body_upload_file_tests_upload_post.py | 76 ++++++++--------- .../models/http_validation_error.py | 1 + ...odel_with_additional_properties_inlined.py | 1 + .../models/model_with_union_property.py | 1 + .../model_with_union_property_inlined.py | 1 + .../models/post_bodies_multiple_files_body.py | 12 +-- .../models/test_inline_objects_body.py | 1 + .../test_inline_objects_response_200.py | 1 + .../models/validation_error.py | 1 + .../my_enum_api_client/models/a_model.py | 1 + .../models/post_user_list_body.py | 83 +++++++------------ .../models/post_body_multipart_body.py | 19 ++--- integration-tests/pyproject.toml | 14 +--- .../templates/model.py.jinja | 55 +++++++++--- .../union_property.py.jinja | 12 ++- 20 files changed, 260 insertions(+), 128 deletions(-) diff --git a/end_to_end_tests/baseline_openapi_3.0.json b/end_to_end_tests/baseline_openapi_3.0.json index eec3e39ac..40a91f628 100644 --- a/end_to_end_tests/baseline_openapi_3.0.json +++ b/end_to_end_tests/baseline_openapi_3.0.json @@ -476,6 +476,55 @@ } } }, + "/tests/upload/multiple-files-in-object": { + "post": { + "tags": [ + "tests" + ], + "summary": "Array of files in object", + "description": "Upload an array of files as part of an object", + "operationId": "upload_array_of_files_in_object_tests_upload_post", + "parameters": [], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type" : "object", + "files" : { + "type" : "array", + "items" : { + "type" : "string", + "description" : "attachments content", + "format" : "binary" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, "/tests/json_body": { "post": { "tags": [ diff --git a/end_to_end_tests/baseline_openapi_3.1.yaml b/end_to_end_tests/baseline_openapi_3.1.yaml index caddda8eb..ff68931bf 100644 --- a/end_to_end_tests/baseline_openapi_3.1.yaml +++ b/end_to_end_tests/baseline_openapi_3.1.yaml @@ -463,6 +463,55 @@ info: } } }, + "/tests/upload/multiple-files-in-object": { + "post": { + "tags": [ + "tests" + ], + "summary": "Array of files in object", + "description": "Upload an array of files as part of an object", + "operationId": "upload_array_of_files_in_object_tests_upload_post", + "parameters": [ ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "files": { + "type": "array", + "items": { + "type": "string", + "description": "attachments content", + "format": "binary" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, "/tests/json_body": { "post": { "tags": [ diff --git a/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py index 1b91acc98..821489ab4 100644 --- a/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py +++ b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py @@ -20,6 +20,7 @@ test_inline_objects, token_with_cookie_auth_token_with_cookie_get, unsupported_content_tests_unsupported_content_get, + upload_array_of_files_in_object_tests_upload_post, upload_file_tests_upload_post, upload_multiple_files_tests_upload_post, ) @@ -89,6 +90,13 @@ def upload_multiple_files_tests_upload_post(cls) -> types.ModuleType: """ return upload_multiple_files_tests_upload_post + @classmethod + def upload_array_of_files_in_object_tests_upload_post(cls) -> types.ModuleType: + """ + Upload an array of files as part of an object + """ + return upload_array_of_files_in_object_tests_upload_post + @classmethod def json_body_tests_json_body_post(cls) -> types.ModuleType: """ diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py index f354c31c7..cae3ca303 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py @@ -87,6 +87,7 @@ ) from .test_inline_objects_body import TestInlineObjectsBody from .test_inline_objects_response_200 import TestInlineObjectsResponse200 +from .upload_array_of_files_in_object_tests_upload_post_body import UploadArrayOfFilesInObjectTestsUploadPostBody from .validation_error import ValidationError __all__ = ( @@ -167,5 +168,6 @@ "PostResponsesUnionsSimpleBeforeComplexResponse200AType1", "TestInlineObjectsBody", "TestInlineObjectsResponse200", + "UploadArrayOfFilesInObjectTestsUploadPostBody", "ValidationError", ) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index 5a9ba85ae..db3c56629 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -206,6 +206,7 @@ def to_dict(self) -> dict[str, Any]: not_required_nullable_model = self.not_required_nullable_model field_dict: dict[str, Any] = {} + field_dict.update( { "an_enum_value": an_enum_value, diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py index f5db27451..91fe12617 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py @@ -136,6 +136,7 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): field_dict[prop_name] = prop.to_dict() + field_dict.update( { "some_file": some_file, @@ -167,13 +168,17 @@ def to_dict(self) -> dict[str, Any]: return field_dict - def to_multipart(self) -> dict[str, Any]: + def to_multipart(self) -> list[tuple[str, Any]]: + field_list: list[tuple[str, Any]] = [] some_file = self.some_file.to_tuple() + field_list.append(("some_file", some_file)) some_required_number = (None, str(self.some_required_number).encode(), "text/plain") + field_list.append(("some_required_number", some_required_number)) some_object = (None, json.dumps(self.some_object.to_dict()).encode(), "application/json") + field_list.append(("some_object", some_object)) some_nullable_object: tuple[None, bytes, str] if isinstance(self.some_nullable_object, BodyUploadFileTestsUploadPostSomeNullableObject): @@ -181,30 +186,41 @@ def to_multipart(self) -> dict[str, Any]: else: some_nullable_object = (None, str(self.some_nullable_object).encode(), "text/plain") + field_list.append(("some_nullable_object", some_nullable_object)) some_optional_file: Union[Unset, FileJsonType] = UNSET if not isinstance(self.some_optional_file, Unset): some_optional_file = self.some_optional_file.to_tuple() + if some_optional_file is not UNSET: + field_list.append(("some_optional_file", some_optional_file)) some_string = ( self.some_string if isinstance(self.some_string, Unset) else (None, str(self.some_string).encode(), "text/plain") ) + if some_string is not UNSET: + field_list.append(("some_string", some_string)) a_datetime: Union[Unset, bytes] = UNSET if not isinstance(self.a_datetime, Unset): a_datetime = self.a_datetime.isoformat().encode() + if a_datetime is not UNSET: + field_list.append(("a_datetime", a_datetime)) a_date: Union[Unset, bytes] = UNSET if not isinstance(self.a_date, Unset): a_date = self.a_date.isoformat().encode() + if a_date is not UNSET: + field_list.append(("a_date", a_date)) some_number = ( self.some_number if isinstance(self.some_number, Unset) else (None, str(self.some_number).encode(), "text/plain") ) + if some_number is not UNSET: + field_list.append(("some_number", some_number)) some_nullable_number: Union[Unset, tuple[None, bytes, str]] if isinstance(self.some_nullable_number, Unset): @@ -214,14 +230,17 @@ def to_multipart(self) -> dict[str, Any]: else: some_nullable_number = (None, str(self.some_nullable_number).encode(), "text/plain") - some_int_array: Union[Unset, tuple[None, bytes, str]] = UNSET - if not isinstance(self.some_int_array, Unset): - _temp_some_int_array = [] - for some_int_array_item_data in self.some_int_array: - some_int_array_item: Union[None, int] - some_int_array_item = some_int_array_item_data - _temp_some_int_array.append(some_int_array_item) - some_int_array = (None, json.dumps(_temp_some_int_array).encode(), "application/json") + if some_nullable_number is not UNSET: + field_list.append(("some_nullable_number", some_nullable_number)) + for some_int_array_element in self.some_int_array or []: + some_int_array_item: tuple[None, bytes, str] + + if isinstance(some_int_array_element, int): + some_int_array_item = (None, str(some_int_array_element).encode(), "text/plain") + else: + some_int_array_item = (None, str(some_int_array_element).encode(), "text/plain") + + field_list.append(("some_int_array", some_int_array_item)) some_array: Union[Unset, tuple[None, bytes, str]] @@ -236,47 +255,28 @@ def to_multipart(self) -> dict[str, Any]: else: some_array = (None, str(self.some_array).encode(), "text/plain") + if some_array is not UNSET: + field_list.append(("some_array", some_array)) some_optional_object: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.some_optional_object, Unset): some_optional_object = (None, json.dumps(self.some_optional_object.to_dict()).encode(), "application/json") + if some_optional_object is not UNSET: + field_list.append(("some_optional_object", some_optional_object)) some_enum: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.some_enum, Unset): some_enum = (None, str(self.some_enum.value).encode(), "text/plain") + if some_enum is not UNSET: + field_list.append(("some_enum", some_enum)) + field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): field_dict[prop_name] = (None, json.dumps(prop.to_dict()).encode(), "application/json") - field_dict.update( - { - "some_file": some_file, - "some_required_number": some_required_number, - "some_object": some_object, - "some_nullable_object": some_nullable_object, - } - ) - if some_optional_file is not UNSET: - field_dict["some_optional_file"] = some_optional_file - if some_string is not UNSET: - field_dict["some_string"] = some_string - if a_datetime is not UNSET: - field_dict["a_datetime"] = a_datetime - if a_date is not UNSET: - field_dict["a_date"] = a_date - if some_number is not UNSET: - field_dict["some_number"] = some_number - if some_nullable_number is not UNSET: - field_dict["some_nullable_number"] = some_nullable_number - if some_int_array is not UNSET: - field_dict["some_int_array"] = some_int_array - if some_array is not UNSET: - field_dict["some_array"] = some_array - if some_optional_object is not UNSET: - field_dict["some_optional_object"] = some_optional_object - if some_enum is not UNSET: - field_dict["some_enum"] = some_enum - return field_dict + field_list += list(field_dict.items()) + + return field_list @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/http_validation_error.py b/end_to_end_tests/golden-record/my_test_api_client/models/http_validation_error.py index cfe0a9a0c..43009994a 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/http_validation_error.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/http_validation_error.py @@ -30,6 +30,7 @@ def to_dict(self) -> dict[str, Any]: detail.append(detail_item) field_dict: dict[str, Any] = {} + field_dict.update({}) if detail is not UNSET: field_dict["detail"] = detail diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_additional_properties_inlined.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_additional_properties_inlined.py index bcdbf868c..bb70f94a8 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_additional_properties_inlined.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_additional_properties_inlined.py @@ -33,6 +33,7 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): field_dict[prop_name] = prop.to_dict() + field_dict.update({}) if a_number is not UNSET: field_dict["a_number"] = a_number diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py index d704baada..aa3019f97 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py @@ -29,6 +29,7 @@ def to_dict(self) -> dict[str, Any]: a_property = self.a_property.value field_dict: dict[str, Any] = {} + field_dict.update({}) if a_property is not UNSET: field_dict["a_property"] = a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property_inlined.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property_inlined.py index 8011b7707..e2ebb7acd 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property_inlined.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property_inlined.py @@ -34,6 +34,7 @@ def to_dict(self) -> dict[str, Any]: fruit = self.fruit.to_dict() field_dict: dict[str, Any] = {} + field_dict.update({}) if fruit is not UNSET: field_dict["fruit"] = fruit diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py index 5f4aefccc..756eec0f1 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py @@ -30,18 +30,20 @@ def to_dict(self) -> dict[str, Any]: return field_dict - def to_multipart(self) -> dict[str, Any]: + def to_multipart(self) -> list[tuple[str, Any]]: + field_list: list[tuple[str, Any]] = [] a = self.a if isinstance(self.a, Unset) else (None, str(self.a).encode(), "text/plain") + if a is not UNSET: + field_list.append(("a", a)) + field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): field_dict[prop_name] = (None, str(prop).encode(), "text/plain") - field_dict.update({}) - if a is not UNSET: - field_dict["a"] = a + field_list += list(field_dict.items()) - return field_dict + return field_list @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_body.py index e03ada2ef..66b4b3dcc 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_body.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_body.py @@ -21,6 +21,7 @@ def to_dict(self) -> dict[str, Any]: a_property = self.a_property field_dict: dict[str, Any] = {} + field_dict.update({}) if a_property is not UNSET: field_dict["a_property"] = a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_response_200.py b/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_response_200.py index 02d7888ea..37c3005c2 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_response_200.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_response_200.py @@ -21,6 +21,7 @@ def to_dict(self) -> dict[str, Any]: a_property = self.a_property field_dict: dict[str, Any] = {} + field_dict.update({}) if a_property is not UNSET: field_dict["a_property"] = a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/validation_error.py b/end_to_end_tests/golden-record/my_test_api_client/models/validation_error.py index 3c8fc9d04..613e44d4e 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/validation_error.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/validation_error.py @@ -27,6 +27,7 @@ def to_dict(self) -> dict[str, Any]: type_ = self.type_ field_dict: dict[str, Any] = {} + field_dict.update( { "loc": loc, diff --git a/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/a_model.py b/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/a_model.py index 881286e74..5c3508cf5 100644 --- a/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/a_model.py +++ b/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/a_model.py @@ -52,6 +52,7 @@ def to_dict(self) -> dict[str, Any]: nested_list_of_enums.append(nested_list_of_enums_item) field_dict: dict[str, Any] = {} + field_dict.update( { "an_enum_value": an_enum_value, diff --git a/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py b/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py index bfddb8c02..8b0788c5e 100644 --- a/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py +++ b/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py @@ -94,35 +94,27 @@ def to_dict(self) -> dict[str, Any]: return field_dict - def to_multipart(self) -> dict[str, Any]: - an_enum_value: Union[Unset, tuple[None, bytes, str]] = UNSET - if not isinstance(self.an_enum_value, Unset): - _temp_an_enum_value = [] - for an_enum_value_item_data in self.an_enum_value: - an_enum_value_item: str = an_enum_value_item_data - _temp_an_enum_value.append(an_enum_value_item) - an_enum_value = (None, json.dumps(_temp_an_enum_value).encode(), "application/json") + def to_multipart(self) -> list[tuple[str, Any]]: + field_list: list[tuple[str, Any]] = [] + for an_enum_value_element in self.an_enum_value or []: + an_enum_value_item = (None, str(an_enum_value_element).encode(), "text/plain") - an_enum_value_with_null: Union[Unset, tuple[None, bytes, str]] = UNSET - if not isinstance(self.an_enum_value_with_null, Unset): - _temp_an_enum_value_with_null = [] - for an_enum_value_with_null_item_data in self.an_enum_value_with_null: - an_enum_value_with_null_item: Union[None, str] - if isinstance(an_enum_value_with_null_item_data, str): - an_enum_value_with_null_item = an_enum_value_with_null_item_data - else: - an_enum_value_with_null_item = an_enum_value_with_null_item_data - _temp_an_enum_value_with_null.append(an_enum_value_with_null_item) - an_enum_value_with_null = (None, json.dumps(_temp_an_enum_value_with_null).encode(), "application/json") + field_list.append(("an_enum_value", an_enum_value_item)) - an_enum_value_with_only_null: Union[Unset, tuple[None, bytes, str]] = UNSET - if not isinstance(self.an_enum_value_with_only_null, Unset): - _temp_an_enum_value_with_only_null = self.an_enum_value_with_only_null - an_enum_value_with_only_null = ( - None, - json.dumps(_temp_an_enum_value_with_only_null).encode(), - "application/json", - ) + for an_enum_value_with_null_element in self.an_enum_value_with_null or []: + an_enum_value_with_null_item: tuple[None, bytes, str] + + if an_enum_value_with_null_element is None: + an_enum_value_with_null_item = (None, str(an_enum_value_with_null_element).encode(), "text/plain") + else: + an_enum_value_with_null_item = (None, str(an_enum_value_with_null_element).encode(), "text/plain") + + field_list.append(("an_enum_value_with_null", an_enum_value_with_null_item)) + + for an_enum_value_with_only_null_element in self.an_enum_value_with_only_null or []: + an_enum_value_with_only_null_item = (None, str(an_enum_value_with_only_null_element).encode(), "text/plain") + + field_list.append(("an_enum_value_with_only_null", an_enum_value_with_only_null_item)) an_allof_enum_with_overridden_default: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.an_allof_enum_with_overridden_default, Unset): @@ -132,41 +124,30 @@ def to_multipart(self) -> dict[str, Any]: "text/plain", ) + if an_allof_enum_with_overridden_default is not UNSET: + field_list.append(("an_allof_enum_with_overridden_default", an_allof_enum_with_overridden_default)) an_optional_allof_enum: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.an_optional_allof_enum, Unset): an_optional_allof_enum = (None, str(self.an_optional_allof_enum).encode(), "text/plain") - nested_list_of_enums: Union[Unset, tuple[None, bytes, str]] = UNSET - if not isinstance(self.nested_list_of_enums, Unset): - _temp_nested_list_of_enums = [] - for nested_list_of_enums_item_data in self.nested_list_of_enums: - nested_list_of_enums_item = [] - for nested_list_of_enums_item_item_data in nested_list_of_enums_item_data: - nested_list_of_enums_item_item: str = nested_list_of_enums_item_item_data - nested_list_of_enums_item.append(nested_list_of_enums_item_item) + if an_optional_allof_enum is not UNSET: + field_list.append(("an_optional_allof_enum", an_optional_allof_enum)) + for nested_list_of_enums_element in self.nested_list_of_enums or []: + _temp_nested_list_of_enums_item = [] + for nested_list_of_enums_item_item_data in nested_list_of_enums_element: + nested_list_of_enums_item_item: str = nested_list_of_enums_item_item_data + _temp_nested_list_of_enums_item.append(nested_list_of_enums_item_item) + nested_list_of_enums_item = (None, json.dumps(_temp_nested_list_of_enums_item).encode(), "application/json") - _temp_nested_list_of_enums.append(nested_list_of_enums_item) - nested_list_of_enums = (None, json.dumps(_temp_nested_list_of_enums).encode(), "application/json") + field_list.append(("nested_list_of_enums", nested_list_of_enums_item)) field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): field_dict[prop_name] = (None, str(prop).encode(), "text/plain") - field_dict.update({}) - if an_enum_value is not UNSET: - field_dict["an_enum_value"] = an_enum_value - if an_enum_value_with_null is not UNSET: - field_dict["an_enum_value_with_null"] = an_enum_value_with_null - if an_enum_value_with_only_null is not UNSET: - field_dict["an_enum_value_with_only_null"] = an_enum_value_with_only_null - if an_allof_enum_with_overridden_default is not UNSET: - field_dict["an_allof_enum_with_overridden_default"] = an_allof_enum_with_overridden_default - if an_optional_allof_enum is not UNSET: - field_dict["an_optional_allof_enum"] = an_optional_allof_enum - if nested_list_of_enums is not UNSET: - field_dict["nested_list_of_enums"] = nested_list_of_enums + field_list += list(field_dict.items()) - return field_dict + return field_list @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: diff --git a/integration-tests/integration_tests/models/post_body_multipart_body.py b/integration-tests/integration_tests/models/post_body_multipart_body.py index f2100a10e..912137295 100644 --- a/integration-tests/integration_tests/models/post_body_multipart_body.py +++ b/integration-tests/integration_tests/models/post_body_multipart_body.py @@ -45,31 +45,30 @@ def to_dict(self) -> dict[str, Any]: return field_dict - def to_multipart(self) -> dict[str, Any]: + def to_multipart(self) -> list[tuple[str, Any]]: + field_list: list[tuple[str, Any]] = [] a_string = (None, str(self.a_string).encode(), "text/plain") + field_list.append(("a_string", a_string)) file = self.file.to_tuple() + field_list.append(("file", file)) description = ( self.description if isinstance(self.description, Unset) else (None, str(self.description).encode(), "text/plain") ) + if description is not UNSET: + field_list.append(("description", description)) + field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): field_dict[prop_name] = (None, str(prop).encode(), "text/plain") - field_dict.update( - { - "a_string": a_string, - "file": file, - } - ) - if description is not UNSET: - field_dict["description"] = description + field_list += list(field_dict.items()) - return field_dict + return field_list @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: diff --git a/integration-tests/pyproject.toml b/integration-tests/pyproject.toml index 536a55b32..6052a3d70 100644 --- a/integration-tests/pyproject.toml +++ b/integration-tests/pyproject.toml @@ -14,22 +14,12 @@ dependencies = [ [tool.pdm] distribution = true -[tool.pdm.dev-dependencies] -dev = [ - "pytest", - "mypy", - "pytest-asyncio>=0.23.5", -] - [build-system] requires = ["pdm-backend"] build-backend = "pdm.backend" - + [tool.ruff] line-length = 120 [tool.ruff.lint] -select = ["F", "I"] - -[tool.mypy] -# Just to get mypy to _not_ look at the parent directory's config \ No newline at end of file +select = ["F", "I", "UP"] diff --git a/openapi_python_client/templates/model.py.jinja b/openapi_python_client/templates/model.py.jinja index eed2ea3a0..b2e082b6a 100644 --- a/openapi_python_client/templates/model.py.jinja +++ b/openapi_python_client/templates/model.py.jinja @@ -82,19 +82,19 @@ class {{ class_name }}: additional_properties: dict[str, {{ additional_property_type }}] = _attrs_field(init=False, factory=dict) {% endif %} -{% macro _to_dict(multipart=False) %} -{% for property in model.required_properties + model.optional_properties %} +{% macro _transform_property(property, content, multipart=False) %} {% import "property_templates/" + property.template as prop_template %} {% if multipart %} -{{ prop_template.transform_multipart(property, "self." + property.python_name, property.python_name) }} +{{ prop_template.transform_multipart(property, content, property.python_name) }} {% elif prop_template.transform %} -{{ prop_template.transform(property=property, source="self." + property.python_name, destination=property.python_name) }} +{{ prop_template.transform(property=property, source=content, destination=property.python_name) }} {% else %} -{{ property.python_name }} = self.{{ property.python_name }} +{{ property.python_name }} = {{ content }} {% endif %} -{% endfor %} +{% endmacro %} +{% macro _prepare_field_dict(multipart=False) %} field_dict: dict[str, Any] = {} {% if model.additional_properties %} {% import "property_templates/" + model.additional_properties.template as prop_template %} @@ -106,8 +106,16 @@ for prop_name, prop in self.additional_properties.items(): {{ prop_template.transform(model.additional_properties, "prop", "field_dict[prop_name]", declare_type=false) | indent(4) }} {% else %} field_dict.update(self.additional_properties) -{% endif %} -{% endif %} +{%- endif -%} +{%- endif -%} +{% endmacro %} + +{% macro _to_dict() %} +{% for property in model.required_properties + model.optional_properties -%} +{{ _transform_property(property, "self." + property.python_name) }} +{% endfor %} + +{{ _prepare_field_dict() }} {% if model.required_properties | length > 0 or model.optional_properties | length > 0 %} field_dict.update({ {% for property in model.required_properties + model.optional_properties %} @@ -134,8 +142,35 @@ return field_dict {{ _to_dict() | indent(8) }} {% if model.is_multipart_body %} - def to_multipart(self) -> dict[str, Any]: - {{ _to_dict(multipart=True) | indent(8) }} + def to_multipart(self) -> list[tuple[str, Any]]: + field_list: list[tuple[str, Any]] = [] + {% for property in model.required_properties + model.optional_properties %} + {% if property.__class__.__name__ == 'ListProperty' %} + {% if not property.required %} + for {{ property.python_name }}_element in self.{{ property.python_name }} or []: + {% else %} + for {{ property.python_name }}_element in self.{{ property.python_name }}: + {% endif %} + {{ _transform_property(property.inner_property, property.python_name + "_element", True) | indent(12) }} + field_list.append(("{{ property.python_name }}", {{property.inner_property.python_name}})) + + {% else %} + {{ _transform_property(property, "self." + property.python_name, True) | indent(8) }} + {% if not property.required %} + if {{ property.python_name }} is not UNSET: + field_list.append(("{{ property.python_name }}", {{property.python_name}})) + {% else %} + field_list.append(("{{ property.python_name }}", {{property.python_name}})) + {% endif %} + {% endif %} + {% endfor %} + + {{ _prepare_field_dict(True) | indent(8) }} + + field_list += list(field_dict.items()) + + return field_list + {% endif %} @classmethod diff --git a/openapi_python_client/templates/property_templates/union_property.py.jinja b/openapi_python_client/templates/property_templates/union_property.py.jinja index dbf7ee9dc..1881d3eae 100644 --- a/openapi_python_client/templates/property_templates/union_property.py.jinja +++ b/openapi_python_client/templates/property_templates/union_property.py.jinja @@ -75,6 +75,14 @@ else: {% endmacro %} +{% macro instance_check(inner_property, source) %} +{% if inner_property.get_instance_type_string() == "None" %} +if {{ source }} is None: +{% else %} +if isinstance({{ source }}, {{ inner_property.get_instance_type_string() }}): +{% endif %} +{% endmacro %} + {% macro transform_multipart(property, source, destination) %} {% set ns = namespace(has_if = false) %} {{ destination }}: {{ property.get_type_string(json=False, multipart=True) }} @@ -86,10 +94,10 @@ if isinstance({{ source }}, Unset): {% endif %} {% for inner_property in property.inner_properties %} {% if not ns.has_if %} -if isinstance({{ source }}, {{ inner_property.get_instance_type_string() }}): +{{ instance_check(inner_property, source) }} {% set ns.has_if = true %} {% elif not loop.last %} -elif isinstance({{ source }}, {{ inner_property.get_instance_type_string() }}): +el{{ instance_check(inner_property, source) }} {% else %} else: {% endif %} From 5840d9118a27f1291cb3a91c07cb4d899cfacca5 Mon Sep 17 00:00:00 2001 From: Dylan Anthony Date: Wed, 14 May 2025 21:02:38 -0600 Subject: [PATCH 2/6] Revert change to integration test pyproject.toml --- integration-tests/pyproject.toml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/integration-tests/pyproject.toml b/integration-tests/pyproject.toml index 6052a3d70..536a55b32 100644 --- a/integration-tests/pyproject.toml +++ b/integration-tests/pyproject.toml @@ -14,12 +14,22 @@ dependencies = [ [tool.pdm] distribution = true +[tool.pdm.dev-dependencies] +dev = [ + "pytest", + "mypy", + "pytest-asyncio>=0.23.5", +] + [build-system] requires = ["pdm-backend"] build-backend = "pdm.backend" - + [tool.ruff] line-length = 120 [tool.ruff.lint] -select = ["F", "I", "UP"] +select = ["F", "I"] + +[tool.mypy] +# Just to get mypy to _not_ look at the parent directory's config \ No newline at end of file From 0eba399dda0bbb28fb29aac31e2d67b2e38872cd Mon Sep 17 00:00:00 2001 From: Dylan Anthony Date: Wed, 14 May 2025 21:02:45 -0600 Subject: [PATCH 3/6] Refresh snapshots --- ...ay_of_files_in_object_tests_upload_post.py | 172 ++++++++++++++++++ ..._files_in_object_tests_upload_post_body.py | 55 ++++++ 2 files changed, 227 insertions(+) create mode 100644 end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_array_of_files_in_object_tests_upload_post.py create mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/upload_array_of_files_in_object_tests_upload_post_body.py diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_array_of_files_in_object_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_array_of_files_in_object_tests_upload_post.py new file mode 100644 index 000000000..4549d1929 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_array_of_files_in_object_tests_upload_post.py @@ -0,0 +1,172 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.http_validation_error import HTTPValidationError +from ...models.upload_array_of_files_in_object_tests_upload_post_body import ( + UploadArrayOfFilesInObjectTestsUploadPostBody, +) +from ...types import Response + + +def _get_kwargs( + *, + body: UploadArrayOfFilesInObjectTestsUploadPostBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tests/upload/multiple-files-in-object", + } + + _body = body.to_multipart() + + _kwargs["files"] = _body + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, HTTPValidationError]]: + if response.status_code == 200: + response_200 = response.json() + return response_200 + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, HTTPValidationError]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: UploadArrayOfFilesInObjectTestsUploadPostBody, +) -> Response[Union[Any, HTTPValidationError]]: + """Array of files in object + + Upload an array of files as part of an object + + Args: + body (UploadArrayOfFilesInObjectTestsUploadPostBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: UploadArrayOfFilesInObjectTestsUploadPostBody, +) -> Optional[Union[Any, HTTPValidationError]]: + """Array of files in object + + Upload an array of files as part of an object + + Args: + body (UploadArrayOfFilesInObjectTestsUploadPostBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, HTTPValidationError] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: UploadArrayOfFilesInObjectTestsUploadPostBody, +) -> Response[Union[Any, HTTPValidationError]]: + """Array of files in object + + Upload an array of files as part of an object + + Args: + body (UploadArrayOfFilesInObjectTestsUploadPostBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + body: UploadArrayOfFilesInObjectTestsUploadPostBody, +) -> Optional[Union[Any, HTTPValidationError]]: + """Array of files in object + + Upload an array of files as part of an object + + Args: + body (UploadArrayOfFilesInObjectTestsUploadPostBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, HTTPValidationError] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/upload_array_of_files_in_object_tests_upload_post_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/upload_array_of_files_in_object_tests_upload_post_body.py new file mode 100644 index 000000000..7901ab355 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/upload_array_of_files_in_object_tests_upload_post_body.py @@ -0,0 +1,55 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UploadArrayOfFilesInObjectTestsUploadPostBody") + + +@_attrs_define +class UploadArrayOfFilesInObjectTestsUploadPostBody: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + def to_multipart(self) -> list[tuple[str, Any]]: + field_list: list[tuple[str, Any]] = [] + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = (None, str(prop).encode(), "text/plain") + + field_list += list(field_dict.items()) + + return field_list + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + upload_array_of_files_in_object_tests_upload_post_body = cls() + + upload_array_of_files_in_object_tests_upload_post_body.additional_properties = d + return upload_array_of_files_in_object_tests_upload_post_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties From d24b3e56110e8f2fd5930d408729956168325aca Mon Sep 17 00:00:00 2001 From: Dylan Anthony Date: Wed, 14 May 2025 21:56:05 -0600 Subject: [PATCH 4/6] Improve grouping of each multipart field --- .../body_upload_file_tests_upload_post.py | 30 +++++++++---------- .../models/post_bodies_multiple_files_body.py | 1 + .../models/post_user_list_body.py | 6 ++-- .../models/post_body_multipart_body.py | 4 ++- .../templates/model.py.jinja | 12 ++++---- .../property_templates/file_property.py.jinja | 4 +-- .../float_property.py.jinja | 2 +- .../union_property.py.jinja | 5 ++-- 8 files changed, 35 insertions(+), 29 deletions(-) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py index 91fe12617..4f697b4c4 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py @@ -170,29 +170,29 @@ def to_dict(self) -> dict[str, Any]: def to_multipart(self) -> list[tuple[str, Any]]: field_list: list[tuple[str, Any]] = [] - some_file = self.some_file.to_tuple() + some_file = self.some_file.to_tuple() field_list.append(("some_file", some_file)) - some_required_number = (None, str(self.some_required_number).encode(), "text/plain") + some_required_number = (None, str(self.some_required_number).encode(), "text/plain") field_list.append(("some_required_number", some_required_number)) - some_object = (None, json.dumps(self.some_object.to_dict()).encode(), "application/json") + some_object = (None, json.dumps(self.some_object.to_dict()).encode(), "application/json") field_list.append(("some_object", some_object)) - some_nullable_object: tuple[None, bytes, str] + some_nullable_object: tuple[None, bytes, str] if isinstance(self.some_nullable_object, BodyUploadFileTestsUploadPostSomeNullableObject): some_nullable_object = (None, json.dumps(self.some_nullable_object.to_dict()).encode(), "application/json") else: some_nullable_object = (None, str(self.some_nullable_object).encode(), "text/plain") - field_list.append(("some_nullable_object", some_nullable_object)) + some_optional_file: Union[Unset, FileJsonType] = UNSET if not isinstance(self.some_optional_file, Unset): some_optional_file = self.some_optional_file.to_tuple() - if some_optional_file is not UNSET: field_list.append(("some_optional_file", some_optional_file)) + some_string = ( self.some_string if isinstance(self.some_string, Unset) @@ -201,18 +201,19 @@ def to_multipart(self) -> list[tuple[str, Any]]: if some_string is not UNSET: field_list.append(("some_string", some_string)) + a_datetime: Union[Unset, bytes] = UNSET if not isinstance(self.a_datetime, Unset): a_datetime = self.a_datetime.isoformat().encode() - if a_datetime is not UNSET: field_list.append(("a_datetime", a_datetime)) + a_date: Union[Unset, bytes] = UNSET if not isinstance(self.a_date, Unset): a_date = self.a_date.isoformat().encode() - if a_date is not UNSET: field_list.append(("a_date", a_date)) + some_number = ( self.some_number if isinstance(self.some_number, Unset) @@ -221,31 +222,30 @@ def to_multipart(self) -> list[tuple[str, Any]]: if some_number is not UNSET: field_list.append(("some_number", some_number)) - some_nullable_number: Union[Unset, tuple[None, bytes, str]] + some_nullable_number: Union[Unset, tuple[None, bytes, str]] if isinstance(self.some_nullable_number, Unset): some_nullable_number = UNSET + elif isinstance(self.some_nullable_number, float): some_nullable_number = (None, str(self.some_nullable_number).encode(), "text/plain") else: some_nullable_number = (None, str(self.some_nullable_number).encode(), "text/plain") - if some_nullable_number is not UNSET: field_list.append(("some_nullable_number", some_nullable_number)) + for some_int_array_element in self.some_int_array or []: some_int_array_item: tuple[None, bytes, str] - if isinstance(some_int_array_element, int): some_int_array_item = (None, str(some_int_array_element).encode(), "text/plain") else: some_int_array_item = (None, str(some_int_array_element).encode(), "text/plain") - field_list.append(("some_int_array", some_int_array_item)) some_array: Union[Unset, tuple[None, bytes, str]] - if isinstance(self.some_array, Unset): some_array = UNSET + elif isinstance(self.some_array, list): _temp_some_array = [] for some_array_type_0_item_data in self.some_array: @@ -254,15 +254,15 @@ def to_multipart(self) -> list[tuple[str, Any]]: some_array = (None, json.dumps(_temp_some_array).encode(), "application/json") else: some_array = (None, str(self.some_array).encode(), "text/plain") - if some_array is not UNSET: field_list.append(("some_array", some_array)) + some_optional_object: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.some_optional_object, Unset): some_optional_object = (None, json.dumps(self.some_optional_object.to_dict()).encode(), "application/json") - if some_optional_object is not UNSET: field_list.append(("some_optional_object", some_optional_object)) + some_enum: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.some_enum, Unset): some_enum = (None, str(self.some_enum.value).encode(), "text/plain") diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py index 756eec0f1..e89fcfc90 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py @@ -32,6 +32,7 @@ def to_dict(self) -> dict[str, Any]: def to_multipart(self) -> list[tuple[str, Any]]: field_list: list[tuple[str, Any]] = [] + a = self.a if isinstance(self.a, Unset) else (None, str(self.a).encode(), "text/plain") if a is not UNSET: diff --git a/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py b/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py index 8b0788c5e..38f8b5c98 100644 --- a/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py +++ b/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py @@ -96,19 +96,17 @@ def to_dict(self) -> dict[str, Any]: def to_multipart(self) -> list[tuple[str, Any]]: field_list: list[tuple[str, Any]] = [] + for an_enum_value_element in self.an_enum_value or []: an_enum_value_item = (None, str(an_enum_value_element).encode(), "text/plain") - field_list.append(("an_enum_value", an_enum_value_item)) for an_enum_value_with_null_element in self.an_enum_value_with_null or []: an_enum_value_with_null_item: tuple[None, bytes, str] - if an_enum_value_with_null_element is None: an_enum_value_with_null_item = (None, str(an_enum_value_with_null_element).encode(), "text/plain") else: an_enum_value_with_null_item = (None, str(an_enum_value_with_null_element).encode(), "text/plain") - field_list.append(("an_enum_value_with_null", an_enum_value_with_null_item)) for an_enum_value_with_only_null_element in self.an_enum_value_with_only_null or []: @@ -126,12 +124,14 @@ def to_multipart(self) -> list[tuple[str, Any]]: if an_allof_enum_with_overridden_default is not UNSET: field_list.append(("an_allof_enum_with_overridden_default", an_allof_enum_with_overridden_default)) + an_optional_allof_enum: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.an_optional_allof_enum, Unset): an_optional_allof_enum = (None, str(self.an_optional_allof_enum).encode(), "text/plain") if an_optional_allof_enum is not UNSET: field_list.append(("an_optional_allof_enum", an_optional_allof_enum)) + for nested_list_of_enums_element in self.nested_list_of_enums or []: _temp_nested_list_of_enums_item = [] for nested_list_of_enums_item_item_data in nested_list_of_enums_element: diff --git a/integration-tests/integration_tests/models/post_body_multipart_body.py b/integration-tests/integration_tests/models/post_body_multipart_body.py index 912137295..f82e46777 100644 --- a/integration-tests/integration_tests/models/post_body_multipart_body.py +++ b/integration-tests/integration_tests/models/post_body_multipart_body.py @@ -47,12 +47,14 @@ def to_dict(self) -> dict[str, Any]: def to_multipart(self) -> list[tuple[str, Any]]: field_list: list[tuple[str, Any]] = [] + a_string = (None, str(self.a_string).encode(), "text/plain") field_list.append(("a_string", a_string)) - file = self.file.to_tuple() + file = self.file.to_tuple() field_list.append(("file", file)) + description = ( self.description if isinstance(self.description, Unset) diff --git a/openapi_python_client/templates/model.py.jinja b/openapi_python_client/templates/model.py.jinja index b2e082b6a..02342af03 100644 --- a/openapi_python_client/templates/model.py.jinja +++ b/openapi_python_client/templates/model.py.jinja @@ -84,14 +84,13 @@ class {{ class_name }}: {% macro _transform_property(property, content, multipart=False) %} {% import "property_templates/" + property.template as prop_template %} -{% if multipart %} +{%- if multipart -%} {{ prop_template.transform_multipart(property, content, property.python_name) }} -{% elif prop_template.transform %} +{%- elif prop_template.transform -%} {{ prop_template.transform(property=property, source=content, destination=property.python_name) }} -{% else %} +{%- else -%} {{ property.python_name }} = {{ content }} -{% endif %} - +{%- endif -%} {% endmacro %} {% macro _prepare_field_dict(multipart=False) %} @@ -113,6 +112,7 @@ field_dict.update(self.additional_properties) {% macro _to_dict() %} {% for property in model.required_properties + model.optional_properties -%} {{ _transform_property(property, "self." + property.python_name) }} + {% endfor %} {{ _prepare_field_dict() }} @@ -144,6 +144,7 @@ return field_dict {% if model.is_multipart_body %} def to_multipart(self) -> list[tuple[str, Any]]: field_list: list[tuple[str, Any]] = [] + {% for property in model.required_properties + model.optional_properties %} {% if property.__class__.__name__ == 'ListProperty' %} {% if not property.required %} @@ -163,6 +164,7 @@ return field_dict field_list.append(("{{ property.python_name }}", {{property.python_name}})) {% endif %} {% endif %} + {% endfor %} {{ _prepare_field_dict(True) | indent(8) }} diff --git a/openapi_python_client/templates/property_templates/file_property.py.jinja b/openapi_python_client/templates/property_templates/file_property.py.jinja index 8d27ae617..c72adcda4 100644 --- a/openapi_python_client/templates/property_templates/file_property.py.jinja +++ b/openapi_python_client/templates/property_templates/file_property.py.jinja @@ -25,9 +25,9 @@ if not isinstance({{ source }}, Unset): {% macro transform_multipart(property, source, destination) %} {% if property.required %} {{ destination }} = {{ source }}.to_tuple() -{% else %} +{%- else %} {{ destination }}: {{ property.get_type_string(json=True) }} = UNSET if not isinstance({{ source }}, Unset): {{ destination }} = {{ source }}.to_tuple() -{% endif %} +{%- endif -%} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/float_property.py.jinja b/openapi_python_client/templates/property_templates/float_property.py.jinja index 12ffb0fb4..88b8404b2 100644 --- a/openapi_python_client/templates/property_templates/float_property.py.jinja +++ b/openapi_python_client/templates/property_templates/float_property.py.jinja @@ -7,5 +7,5 @@ str({{ source }}) {{ destination }} = {{source}} if isinstance({{source}}, Unset) else (None, str({{source}}).encode(), "text/plain") {% else %} {{ destination }} = (None, str({{ source }}).encode(), "text/plain") -{% endif %} +{%- endif -%} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/union_property.py.jinja b/openapi_python_client/templates/property_templates/union_property.py.jinja index 1881d3eae..b39e2d5cc 100644 --- a/openapi_python_client/templates/property_templates/union_property.py.jinja +++ b/openapi_python_client/templates/property_templates/union_property.py.jinja @@ -86,7 +86,6 @@ if isinstance({{ source }}, {{ inner_property.get_instance_type_string() }}): {% macro transform_multipart(property, source, destination) %} {% set ns = namespace(has_if = false) %} {{ destination }}: {{ property.get_type_string(json=False, multipart=True) }} - {% if not property.required %} if isinstance({{ source }}, Unset): {{ destination }} = UNSET @@ -97,11 +96,13 @@ if isinstance({{ source }}, Unset): {{ instance_check(inner_property, source) }} {% set ns.has_if = true %} {% elif not loop.last %} + el{{ instance_check(inner_property, source) }} {% else %} + else: {% endif %} {% import "property_templates/" + inner_property.template as inner_template %} {{ inner_template.transform_multipart(inner_property, source, destination) | indent(4) | trim }} -{% endfor %} +{%- endfor -%} {% endmacro %} From 2f196acb57276228809b7ec056f858212a1d7529 Mon Sep 17 00:00:00 2001 From: Dylan Anthony Date: Fri, 16 May 2025 20:06:01 -0600 Subject: [PATCH 5/6] Remove faulty test case. Arrays of files are being tested in other endpoints, and this one was slightly malformed. --- end_to_end_tests/baseline_openapi_3.0.json | 49 ----- end_to_end_tests/baseline_openapi_3.1.yaml | 49 ----- .../my_test_api_client/api/tests/__init__.py | 8 - ...ay_of_files_in_object_tests_upload_post.py | 172 ------------------ .../my_test_api_client/models/__init__.py | 2 - ..._files_in_object_tests_upload_post_body.py | 55 ------ 6 files changed, 335 deletions(-) delete mode 100644 end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_array_of_files_in_object_tests_upload_post.py delete mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/upload_array_of_files_in_object_tests_upload_post_body.py diff --git a/end_to_end_tests/baseline_openapi_3.0.json b/end_to_end_tests/baseline_openapi_3.0.json index 40a91f628..eec3e39ac 100644 --- a/end_to_end_tests/baseline_openapi_3.0.json +++ b/end_to_end_tests/baseline_openapi_3.0.json @@ -476,55 +476,6 @@ } } }, - "/tests/upload/multiple-files-in-object": { - "post": { - "tags": [ - "tests" - ], - "summary": "Array of files in object", - "description": "Upload an array of files as part of an object", - "operationId": "upload_array_of_files_in_object_tests_upload_post", - "parameters": [], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type" : "object", - "files" : { - "type" : "array", - "items" : { - "type" : "string", - "description" : "attachments content", - "format" : "binary" - } - } - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, "/tests/json_body": { "post": { "tags": [ diff --git a/end_to_end_tests/baseline_openapi_3.1.yaml b/end_to_end_tests/baseline_openapi_3.1.yaml index ff68931bf..caddda8eb 100644 --- a/end_to_end_tests/baseline_openapi_3.1.yaml +++ b/end_to_end_tests/baseline_openapi_3.1.yaml @@ -463,55 +463,6 @@ info: } } }, - "/tests/upload/multiple-files-in-object": { - "post": { - "tags": [ - "tests" - ], - "summary": "Array of files in object", - "description": "Upload an array of files as part of an object", - "operationId": "upload_array_of_files_in_object_tests_upload_post", - "parameters": [ ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "files": { - "type": "array", - "items": { - "type": "string", - "description": "attachments content", - "format": "binary" - } - } - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, "/tests/json_body": { "post": { "tags": [ diff --git a/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py index 821489ab4..1b91acc98 100644 --- a/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py +++ b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py @@ -20,7 +20,6 @@ test_inline_objects, token_with_cookie_auth_token_with_cookie_get, unsupported_content_tests_unsupported_content_get, - upload_array_of_files_in_object_tests_upload_post, upload_file_tests_upload_post, upload_multiple_files_tests_upload_post, ) @@ -90,13 +89,6 @@ def upload_multiple_files_tests_upload_post(cls) -> types.ModuleType: """ return upload_multiple_files_tests_upload_post - @classmethod - def upload_array_of_files_in_object_tests_upload_post(cls) -> types.ModuleType: - """ - Upload an array of files as part of an object - """ - return upload_array_of_files_in_object_tests_upload_post - @classmethod def json_body_tests_json_body_post(cls) -> types.ModuleType: """ diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_array_of_files_in_object_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_array_of_files_in_object_tests_upload_post.py deleted file mode 100644 index 4549d1929..000000000 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_array_of_files_in_object_tests_upload_post.py +++ /dev/null @@ -1,172 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.http_validation_error import HTTPValidationError -from ...models.upload_array_of_files_in_object_tests_upload_post_body import ( - UploadArrayOfFilesInObjectTestsUploadPostBody, -) -from ...types import Response - - -def _get_kwargs( - *, - body: UploadArrayOfFilesInObjectTestsUploadPostBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/tests/upload/multiple-files-in-object", - } - - _body = body.to_multipart() - - _kwargs["files"] = _body - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, HTTPValidationError]]: - if response.status_code == 200: - response_200 = response.json() - return response_200 - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, HTTPValidationError]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: Union[AuthenticatedClient, Client], - body: UploadArrayOfFilesInObjectTestsUploadPostBody, -) -> Response[Union[Any, HTTPValidationError]]: - """Array of files in object - - Upload an array of files as part of an object - - Args: - body (UploadArrayOfFilesInObjectTestsUploadPostBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: Union[AuthenticatedClient, Client], - body: UploadArrayOfFilesInObjectTestsUploadPostBody, -) -> Optional[Union[Any, HTTPValidationError]]: - """Array of files in object - - Upload an array of files as part of an object - - Args: - body (UploadArrayOfFilesInObjectTestsUploadPostBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, HTTPValidationError] - """ - - return sync_detailed( - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - *, - client: Union[AuthenticatedClient, Client], - body: UploadArrayOfFilesInObjectTestsUploadPostBody, -) -> Response[Union[Any, HTTPValidationError]]: - """Array of files in object - - Upload an array of files as part of an object - - Args: - body (UploadArrayOfFilesInObjectTestsUploadPostBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: Union[AuthenticatedClient, Client], - body: UploadArrayOfFilesInObjectTestsUploadPostBody, -) -> Optional[Union[Any, HTTPValidationError]]: - """Array of files in object - - Upload an array of files as part of an object - - Args: - body (UploadArrayOfFilesInObjectTestsUploadPostBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, HTTPValidationError] - """ - - return ( - await asyncio_detailed( - client=client, - body=body, - ) - ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py index cae3ca303..f354c31c7 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py @@ -87,7 +87,6 @@ ) from .test_inline_objects_body import TestInlineObjectsBody from .test_inline_objects_response_200 import TestInlineObjectsResponse200 -from .upload_array_of_files_in_object_tests_upload_post_body import UploadArrayOfFilesInObjectTestsUploadPostBody from .validation_error import ValidationError __all__ = ( @@ -168,6 +167,5 @@ "PostResponsesUnionsSimpleBeforeComplexResponse200AType1", "TestInlineObjectsBody", "TestInlineObjectsResponse200", - "UploadArrayOfFilesInObjectTestsUploadPostBody", "ValidationError", ) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/upload_array_of_files_in_object_tests_upload_post_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/upload_array_of_files_in_object_tests_upload_post_body.py deleted file mode 100644 index 7901ab355..000000000 --- a/end_to_end_tests/golden-record/my_test_api_client/models/upload_array_of_files_in_object_tests_upload_post_body.py +++ /dev/null @@ -1,55 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="UploadArrayOfFilesInObjectTestsUploadPostBody") - - -@_attrs_define -class UploadArrayOfFilesInObjectTestsUploadPostBody: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - def to_multipart(self) -> list[tuple[str, Any]]: - field_list: list[tuple[str, Any]] = [] - - field_dict: dict[str, Any] = {} - for prop_name, prop in self.additional_properties.items(): - field_dict[prop_name] = (None, str(prop).encode(), "text/plain") - - field_list += list(field_dict.items()) - - return field_list - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - upload_array_of_files_in_object_tests_upload_post_body = cls() - - upload_array_of_files_in_object_tests_upload_post_body.additional_properties = d - return upload_array_of_files_in_object_tests_upload_post_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties From 0f8c7fe80acecebc476b2569d5240550d414a333 Mon Sep 17 00:00:00 2001 From: Dylan Anthony Date: Fri, 16 May 2025 21:24:28 -0600 Subject: [PATCH 6/6] Simplify property to multipart code. --- .../body_upload_file_tests_upload_post.py | 137 +++++++----------- .../models/post_bodies_multiple_files_body.py | 11 +- .../models/post_user_list_body.py | 85 ++++++----- .../models/post_body_multipart_body.py | 22 +-- .../templates/model.py.jinja | 50 +++---- .../property_templates/any_property.py.jinja | 8 +- .../boolean_property.py.jinja | 8 +- .../const_property.py.jinja | 4 + .../property_templates/date_property.py.jinja | 11 +- .../datetime_property.py.jinja | 11 +- .../property_templates/enum_property.py.jinja | 11 +- .../property_templates/file_property.py.jinja | 10 +- .../float_property.py.jinja | 8 +- .../property_templates/int_property.py.jinja | 8 +- .../property_templates/list_property.py.jinja | 35 ++--- .../literal_enum_property.py.jinja | 11 +- .../model_property.py.jinja | 11 +- .../union_property.py.jinja | 10 +- .../property_templates/uuid_property.py.jinja | 11 +- 19 files changed, 168 insertions(+), 294 deletions(-) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py index 4f697b4c4..5bc69e864 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py @@ -171,110 +171,83 @@ def to_dict(self) -> dict[str, Any]: def to_multipart(self) -> list[tuple[str, Any]]: field_list: list[tuple[str, Any]] = [] - some_file = self.some_file.to_tuple() - field_list.append(("some_file", some_file)) + field_list.append(("some_file", self.some_file.to_tuple())) - some_required_number = (None, str(self.some_required_number).encode(), "text/plain") - field_list.append(("some_required_number", some_required_number)) + field_list.append(("some_required_number", (None, str(self.some_required_number).encode(), "text/plain"))) - some_object = (None, json.dumps(self.some_object.to_dict()).encode(), "application/json") - field_list.append(("some_object", some_object)) + field_list.append(("some_object", (None, json.dumps(self.some_object.to_dict()).encode(), "application/json"))) - some_nullable_object: tuple[None, bytes, str] if isinstance(self.some_nullable_object, BodyUploadFileTestsUploadPostSomeNullableObject): - some_nullable_object = (None, json.dumps(self.some_nullable_object.to_dict()).encode(), "application/json") + field_list.append( + ( + "some_nullable_object", + (None, json.dumps(self.some_nullable_object.to_dict()).encode(), "application/json"), + ) + ) else: - some_nullable_object = (None, str(self.some_nullable_object).encode(), "text/plain") - field_list.append(("some_nullable_object", some_nullable_object)) + field_list.append(("some_nullable_object", (None, str(self.some_nullable_object).encode(), "text/plain"))) - some_optional_file: Union[Unset, FileJsonType] = UNSET if not isinstance(self.some_optional_file, Unset): - some_optional_file = self.some_optional_file.to_tuple() - if some_optional_file is not UNSET: - field_list.append(("some_optional_file", some_optional_file)) + field_list.append(("some_optional_file", self.some_optional_file.to_tuple())) - some_string = ( - self.some_string - if isinstance(self.some_string, Unset) - else (None, str(self.some_string).encode(), "text/plain") - ) + if not isinstance(self.some_string, Unset): + field_list.append(("some_string", (None, str(self.some_string).encode(), "text/plain"))) - if some_string is not UNSET: - field_list.append(("some_string", some_string)) - - a_datetime: Union[Unset, bytes] = UNSET if not isinstance(self.a_datetime, Unset): - a_datetime = self.a_datetime.isoformat().encode() - if a_datetime is not UNSET: - field_list.append(("a_datetime", a_datetime)) + field_list.append(("a_datetime", self.a_datetime.isoformat().encode())) - a_date: Union[Unset, bytes] = UNSET if not isinstance(self.a_date, Unset): - a_date = self.a_date.isoformat().encode() - if a_date is not UNSET: - field_list.append(("a_date", a_date)) + field_list.append(("a_date", self.a_date.isoformat().encode())) - some_number = ( - self.some_number - if isinstance(self.some_number, Unset) - else (None, str(self.some_number).encode(), "text/plain") - ) - - if some_number is not UNSET: - field_list.append(("some_number", some_number)) - - some_nullable_number: Union[Unset, tuple[None, bytes, str]] - if isinstance(self.some_nullable_number, Unset): - some_nullable_number = UNSET + if not isinstance(self.some_number, Unset): + field_list.append(("some_number", (None, str(self.some_number).encode(), "text/plain"))) - elif isinstance(self.some_nullable_number, float): - some_nullable_number = (None, str(self.some_nullable_number).encode(), "text/plain") - else: - some_nullable_number = (None, str(self.some_nullable_number).encode(), "text/plain") - if some_nullable_number is not UNSET: - field_list.append(("some_nullable_number", some_nullable_number)) - - for some_int_array_element in self.some_int_array or []: - some_int_array_item: tuple[None, bytes, str] - if isinstance(some_int_array_element, int): - some_int_array_item = (None, str(some_int_array_element).encode(), "text/plain") + if not isinstance(self.some_nullable_number, Unset): + if isinstance(self.some_nullable_number, float): + field_list.append( + ("some_nullable_number", (None, str(self.some_nullable_number).encode(), "text/plain")) + ) else: - some_int_array_item = (None, str(some_int_array_element).encode(), "text/plain") - field_list.append(("some_int_array", some_int_array_item)) - - some_array: Union[Unset, tuple[None, bytes, str]] - if isinstance(self.some_array, Unset): - some_array = UNSET + field_list.append( + ("some_nullable_number", (None, str(self.some_nullable_number).encode(), "text/plain")) + ) - elif isinstance(self.some_array, list): - _temp_some_array = [] - for some_array_type_0_item_data in self.some_array: - some_array_type_0_item = some_array_type_0_item_data.to_dict() - _temp_some_array.append(some_array_type_0_item) - some_array = (None, json.dumps(_temp_some_array).encode(), "application/json") - else: - some_array = (None, str(self.some_array).encode(), "text/plain") - if some_array is not UNSET: - field_list.append(("some_array", some_array)) + if not isinstance(self.some_int_array, Unset): + for some_int_array_item_element in self.some_int_array: + if isinstance(some_int_array_item_element, int): + field_list.append( + ("some_int_array", (None, str(some_int_array_item_element).encode(), "text/plain")) + ) + else: + field_list.append( + ("some_int_array", (None, str(some_int_array_item_element).encode(), "text/plain")) + ) + + if not isinstance(self.some_array, Unset): + if isinstance(self.some_array, list): + for some_array_type_0_item_element in self.some_array: + field_list.append( + ( + "some_array", + (None, json.dumps(some_array_type_0_item_element.to_dict()).encode(), "application/json"), + ) + ) + else: + field_list.append(("some_array", (None, str(self.some_array).encode(), "text/plain"))) - some_optional_object: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.some_optional_object, Unset): - some_optional_object = (None, json.dumps(self.some_optional_object.to_dict()).encode(), "application/json") - if some_optional_object is not UNSET: - field_list.append(("some_optional_object", some_optional_object)) + field_list.append( + ( + "some_optional_object", + (None, json.dumps(self.some_optional_object.to_dict()).encode(), "application/json"), + ) + ) - some_enum: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.some_enum, Unset): - some_enum = (None, str(self.some_enum.value).encode(), "text/plain") + field_list.append(("some_enum", (None, str(self.some_enum.value).encode(), "text/plain"))) - if some_enum is not UNSET: - field_list.append(("some_enum", some_enum)) - - field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): - field_dict[prop_name] = (None, json.dumps(prop.to_dict()).encode(), "application/json") - - field_list += list(field_dict.items()) + field_list.append((prop_name, (None, json.dumps(prop.to_dict()).encode(), "application/json"))) return field_list diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py index e89fcfc90..81707d241 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py @@ -33,16 +33,11 @@ def to_dict(self) -> dict[str, Any]: def to_multipart(self) -> list[tuple[str, Any]]: field_list: list[tuple[str, Any]] = [] - a = self.a if isinstance(self.a, Unset) else (None, str(self.a).encode(), "text/plain") + if not isinstance(self.a, Unset): + field_list.append(("a", (None, str(self.a).encode(), "text/plain"))) - if a is not UNSET: - field_list.append(("a", a)) - - field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): - field_dict[prop_name] = (None, str(prop).encode(), "text/plain") - - field_list += list(field_dict.items()) + field_list.append((prop_name, (None, str(prop).encode(), "text/plain"))) return field_list diff --git a/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py b/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py index 38f8b5c98..e582bd869 100644 --- a/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py +++ b/end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py @@ -1,4 +1,3 @@ -import json from collections.abc import Mapping from typing import Any, TypeVar, Union, cast @@ -97,55 +96,61 @@ def to_dict(self) -> dict[str, Any]: def to_multipart(self) -> list[tuple[str, Any]]: field_list: list[tuple[str, Any]] = [] - for an_enum_value_element in self.an_enum_value or []: - an_enum_value_item = (None, str(an_enum_value_element).encode(), "text/plain") - field_list.append(("an_enum_value", an_enum_value_item)) - - for an_enum_value_with_null_element in self.an_enum_value_with_null or []: - an_enum_value_with_null_item: tuple[None, bytes, str] - if an_enum_value_with_null_element is None: - an_enum_value_with_null_item = (None, str(an_enum_value_with_null_element).encode(), "text/plain") - else: - an_enum_value_with_null_item = (None, str(an_enum_value_with_null_element).encode(), "text/plain") - field_list.append(("an_enum_value_with_null", an_enum_value_with_null_item)) + if not isinstance(self.an_enum_value, Unset): + for an_enum_value_item_element in self.an_enum_value: + field_list.append(("an_enum_value", (None, str(an_enum_value_item_element).encode(), "text/plain"))) - for an_enum_value_with_only_null_element in self.an_enum_value_with_only_null or []: - an_enum_value_with_only_null_item = (None, str(an_enum_value_with_only_null_element).encode(), "text/plain") + if not isinstance(self.an_enum_value_with_null, Unset): + for an_enum_value_with_null_item_element in self.an_enum_value_with_null: + if an_enum_value_with_null_item_element is None: + field_list.append( + ( + "an_enum_value_with_null", + (None, str(an_enum_value_with_null_item_element).encode(), "text/plain"), + ) + ) + else: + field_list.append( + ( + "an_enum_value_with_null", + (None, str(an_enum_value_with_null_item_element).encode(), "text/plain"), + ) + ) - field_list.append(("an_enum_value_with_only_null", an_enum_value_with_only_null_item)) + if not isinstance(self.an_enum_value_with_only_null, Unset): + for an_enum_value_with_only_null_item_element in self.an_enum_value_with_only_null: + field_list.append( + ( + "an_enum_value_with_only_null", + (None, str(an_enum_value_with_only_null_item_element).encode(), "text/plain"), + ) + ) - an_allof_enum_with_overridden_default: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.an_allof_enum_with_overridden_default, Unset): - an_allof_enum_with_overridden_default = ( - None, - str(self.an_allof_enum_with_overridden_default).encode(), - "text/plain", + field_list.append( + ( + "an_allof_enum_with_overridden_default", + (None, str(self.an_allof_enum_with_overridden_default).encode(), "text/plain"), + ) ) - if an_allof_enum_with_overridden_default is not UNSET: - field_list.append(("an_allof_enum_with_overridden_default", an_allof_enum_with_overridden_default)) - - an_optional_allof_enum: Union[Unset, tuple[None, bytes, str]] = UNSET if not isinstance(self.an_optional_allof_enum, Unset): - an_optional_allof_enum = (None, str(self.an_optional_allof_enum).encode(), "text/plain") - - if an_optional_allof_enum is not UNSET: - field_list.append(("an_optional_allof_enum", an_optional_allof_enum)) - - for nested_list_of_enums_element in self.nested_list_of_enums or []: - _temp_nested_list_of_enums_item = [] - for nested_list_of_enums_item_item_data in nested_list_of_enums_element: - nested_list_of_enums_item_item: str = nested_list_of_enums_item_item_data - _temp_nested_list_of_enums_item.append(nested_list_of_enums_item_item) - nested_list_of_enums_item = (None, json.dumps(_temp_nested_list_of_enums_item).encode(), "application/json") + field_list.append( + ("an_optional_allof_enum", (None, str(self.an_optional_allof_enum).encode(), "text/plain")) + ) - field_list.append(("nested_list_of_enums", nested_list_of_enums_item)) + if not isinstance(self.nested_list_of_enums, Unset): + for nested_list_of_enums_item_element in self.nested_list_of_enums: + for nested_list_of_enums_item_item_element in nested_list_of_enums_item_element: + field_list.append( + ( + "nested_list_of_enums", + (None, str(nested_list_of_enums_item_item_element).encode(), "text/plain"), + ) + ) - field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): - field_dict[prop_name] = (None, str(prop).encode(), "text/plain") - - field_list += list(field_dict.items()) + field_list.append((prop_name, (None, str(prop).encode(), "text/plain"))) return field_list diff --git a/integration-tests/integration_tests/models/post_body_multipart_body.py b/integration-tests/integration_tests/models/post_body_multipart_body.py index f82e46777..114f632f8 100644 --- a/integration-tests/integration_tests/models/post_body_multipart_body.py +++ b/integration-tests/integration_tests/models/post_body_multipart_body.py @@ -48,27 +48,15 @@ def to_dict(self) -> dict[str, Any]: def to_multipart(self) -> list[tuple[str, Any]]: field_list: list[tuple[str, Any]] = [] - a_string = (None, str(self.a_string).encode(), "text/plain") + field_list.append(("a_string", (None, str(self.a_string).encode(), "text/plain"))) - field_list.append(("a_string", a_string)) + field_list.append(("file", self.file.to_tuple())) - file = self.file.to_tuple() - field_list.append(("file", file)) - - description = ( - self.description - if isinstance(self.description, Unset) - else (None, str(self.description).encode(), "text/plain") - ) + if not isinstance(self.description, Unset): + field_list.append(("description", (None, str(self.description).encode(), "text/plain"))) - if description is not UNSET: - field_list.append(("description", description)) - - field_dict: dict[str, Any] = {} for prop_name, prop in self.additional_properties.items(): - field_dict[prop_name] = (None, str(prop).encode(), "text/plain") - - field_list += list(field_dict.items()) + field_list.append((prop_name, (None, str(prop).encode(), "text/plain"))) return field_list diff --git a/openapi_python_client/templates/model.py.jinja b/openapi_python_client/templates/model.py.jinja index 02342af03..2f48654ec 100644 --- a/openapi_python_client/templates/model.py.jinja +++ b/openapi_python_client/templates/model.py.jinja @@ -82,25 +82,30 @@ class {{ class_name }}: additional_properties: dict[str, {{ additional_property_type }}] = _attrs_field(init=False, factory=dict) {% endif %} -{% macro _transform_property(property, content, multipart=False) %} +{% macro _transform_property(property, content) %} {% import "property_templates/" + property.template as prop_template %} -{%- if multipart -%} -{{ prop_template.transform_multipart(property, content, property.python_name) }} -{%- elif prop_template.transform -%} +{%- if prop_template.transform -%} {{ prop_template.transform(property=property, source=content, destination=property.python_name) }} {%- else -%} {{ property.python_name }} = {{ content }} {%- endif -%} {% endmacro %} -{% macro _prepare_field_dict(multipart=False) %} +{% macro multipart(property, source, destination) %} +{% import "property_templates/" + property.template as prop_template %} +{% if not property.required %} +if not isinstance({{source}}, Unset): + {{ prop_template.multipart(property, source, destination) | indent(4) }} +{% else %} +{{ prop_template.multipart(property, source, destination) }} +{% endif %} +{% endmacro %} + +{% macro _prepare_field_dict() %} field_dict: dict[str, Any] = {} {% if model.additional_properties %} {% import "property_templates/" + model.additional_properties.template as prop_template %} -{% if multipart %} -for prop_name, prop in self.additional_properties.items(): - {{ prop_template.transform_multipart(model.additional_properties, "prop", "field_dict[prop_name]") | indent(4) }} -{% elif prop_template.transform %} +{% if prop_template.transform %} for prop_name, prop in self.additional_properties.items(): {{ prop_template.transform(model.additional_properties, "prop", "field_dict[prop_name]", declare_type=false) | indent(4) }} {% else %} @@ -146,30 +151,15 @@ return field_dict field_list: list[tuple[str, Any]] = [] {% for property in model.required_properties + model.optional_properties %} - {% if property.__class__.__name__ == 'ListProperty' %} - {% if not property.required %} - for {{ property.python_name }}_element in self.{{ property.python_name }} or []: - {% else %} - for {{ property.python_name }}_element in self.{{ property.python_name }}: - {% endif %} - {{ _transform_property(property.inner_property, property.python_name + "_element", True) | indent(12) }} - field_list.append(("{{ property.python_name }}", {{property.inner_property.python_name}})) - - {% else %} - {{ _transform_property(property, "self." + property.python_name, True) | indent(8) }} - {% if not property.required %} - if {{ property.python_name }} is not UNSET: - field_list.append(("{{ property.python_name }}", {{property.python_name}})) - {% else %} - field_list.append(("{{ property.python_name }}", {{property.python_name}})) - {% endif %} - {% endif %} + {% set destination = "\"" + property.name + "\"" %} + {{ multipart(property, "self." + property.python_name, destination) | indent(8) }} {% endfor %} - {{ _prepare_field_dict(True) | indent(8) }} - - field_list += list(field_dict.items()) + {% if model.additional_properties %} + for prop_name, prop in self.additional_properties.items(): + {{ multipart(model.additional_properties, "prop", "prop_name") | indent(4) }} + {% endif %} return field_list diff --git a/openapi_python_client/templates/property_templates/any_property.py.jinja b/openapi_python_client/templates/property_templates/any_property.py.jinja index 25a16516a..0eff2d50e 100644 --- a/openapi_python_client/templates/property_templates/any_property.py.jinja +++ b/openapi_python_client/templates/property_templates/any_property.py.jinja @@ -1,7 +1,3 @@ -{% macro transform_multipart(property, source, destination) %} -{% if not property.required %} -{{ destination }} = {{source}} if isinstance({{source}}, Unset) else (None, str({{source}}).encode(), "text/plain") -{% else %} -{{ destination }} = (None, str({{ source }}).encode(), "text/plain") -{% endif %} +{% macro multipart(property, source, destination) %} +field_list.append(({{ destination }}, (None, str({{source}}).encode(), "text/plain"))) {% endmacro %} \ No newline at end of file diff --git a/openapi_python_client/templates/property_templates/boolean_property.py.jinja b/openapi_python_client/templates/property_templates/boolean_property.py.jinja index 52fda08e1..b9a837e9c 100644 --- a/openapi_python_client/templates/property_templates/boolean_property.py.jinja +++ b/openapi_python_client/templates/property_templates/boolean_property.py.jinja @@ -2,10 +2,6 @@ "true" if {{ source }} else "false" {% endmacro %} -{% macro transform_multipart(property, source, destination) %} -{% if not property.required %} -{{ destination }} = {{source}} if isinstance({{source}}, Unset) else (None, str({{source}}).encode(), "text/plain") -{% else %} -{{ destination }} = (None, str({{ source }}).encode(), "text/plain") -{% endif %} +{% macro multipart(property, source, destination) %} +field_list.append(({{ destination }}, (None, str({{source}}).encode(), "text/plain"))) {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/const_property.py.jinja b/openapi_python_client/templates/property_templates/const_property.py.jinja index fa635b5b9..8ad5bbff9 100644 --- a/openapi_python_client/templates/property_templates/const_property.py.jinja +++ b/openapi_python_client/templates/property_templates/const_property.py.jinja @@ -3,3 +3,7 @@ if {{ property.python_name }} != {{ property.value.python_code }}{% if not property.required %}and not isinstance({{ property.python_name }}, Unset){% endif %}: raise ValueError(f"{{ property.name }} must match const {{ property.value.python_code }}, got '{{'{' + property.python_name + '}' }}'") {%- endmacro %} + +{% macro multipart(property, source, destination) %} +field_list.append(({{ destination }}, source)) +{% endmacro %} diff --git a/openapi_python_client/templates/property_templates/date_property.py.jinja b/openapi_python_client/templates/property_templates/date_property.py.jinja index b5da665f7..bf88444fe 100644 --- a/openapi_python_client/templates/property_templates/date_property.py.jinja +++ b/openapi_python_client/templates/property_templates/date_property.py.jinja @@ -26,14 +26,7 @@ if not isinstance({{ source }}, Unset): {%- endif %} {% endmacro %} -{% macro transform_multipart(property, source, destination) %} +{% macro multipart(property, source, destination) %} {% set transformed = source + ".isoformat().encode()" %} -{% if property.required %} -{{ destination }} = {{ transformed }} -{%- else %} -{% set type_annotation = property.get_type_string(json=True) | replace("str", "bytes") %} -{{ destination }}: {{ type_annotation }} = UNSET -if not isinstance({{ source }}, Unset): - {{ destination }} = {{ transformed }} -{%- endif %} +field_list.append(({{ destination }}, {{ transformed }})) {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/datetime_property.py.jinja b/openapi_python_client/templates/property_templates/datetime_property.py.jinja index 32e3f2ee6..29c38bc97 100644 --- a/openapi_python_client/templates/property_templates/datetime_property.py.jinja +++ b/openapi_python_client/templates/property_templates/datetime_property.py.jinja @@ -26,14 +26,7 @@ if not isinstance({{ source }}, Unset): {%- endif %} {% endmacro %} -{% macro transform_multipart(property, source, destination) %} +{% macro multipart(property, source, destination) %} {% set transformed = source + ".isoformat().encode()" %} -{% if property.required %} -{{ destination }} = {{ transformed }} -{%- else %} -{% set type_annotation = property.get_type_string(json=True) | replace("str", "bytes") %} -{{ destination }}: {{ type_annotation }} = UNSET -if not isinstance({{ source }}, Unset): - {{ destination }} = {{ transformed }} -{%- endif %} +field_list.append(({{ destination }}, {{ transformed }})) {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/enum_property.py.jinja b/openapi_python_client/templates/property_templates/enum_property.py.jinja index c46538eac..aac89aeac 100644 --- a/openapi_python_client/templates/property_templates/enum_property.py.jinja +++ b/openapi_python_client/templates/property_templates/enum_property.py.jinja @@ -22,16 +22,9 @@ if not isinstance({{ source }}, Unset): {% endif %} {% endmacro %} -{% macro transform_multipart(property, source, destination) %} +{% macro multipart(property, source, destination) %} {% set transformed = "(None, str(" + source + ".value" + ").encode(), \"text/plain\")" %} -{% set type_string = "Union[Unset, tuple[None, bytes, str]]" %} -{% if property.required %} -{{ destination }} = {{ transformed }} -{%- else %} -{{ destination }}: {{ type_string }} = UNSET -if not isinstance({{ source }}, Unset): - {{ destination }} = {{ transformed }} -{% endif %} +field_list.append(({{ destination }}, {{ transformed }})) {% endmacro %} {% macro transform_header(source) %} diff --git a/openapi_python_client/templates/property_templates/file_property.py.jinja b/openapi_python_client/templates/property_templates/file_property.py.jinja index c72adcda4..275650db3 100644 --- a/openapi_python_client/templates/property_templates/file_property.py.jinja +++ b/openapi_python_client/templates/property_templates/file_property.py.jinja @@ -22,12 +22,6 @@ if not isinstance({{ source }}, Unset): {% endif %} {% endmacro %} -{% macro transform_multipart(property, source, destination) %} -{% if property.required %} -{{ destination }} = {{ source }}.to_tuple() -{%- else %} -{{ destination }}: {{ property.get_type_string(json=True) }} = UNSET -if not isinstance({{ source }}, Unset): - {{ destination }} = {{ source }}.to_tuple() -{%- endif -%} +{% macro multipart(property, source, destination) %} +field_list.append(({{ destination }}, {{ source }}.to_tuple())) {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/float_property.py.jinja b/openapi_python_client/templates/property_templates/float_property.py.jinja index 88b8404b2..0729c82fb 100644 --- a/openapi_python_client/templates/property_templates/float_property.py.jinja +++ b/openapi_python_client/templates/property_templates/float_property.py.jinja @@ -2,10 +2,6 @@ str({{ source }}) {% endmacro %} -{% macro transform_multipart(property, source, destination) %} -{% if not property.required %} -{{ destination }} = {{source}} if isinstance({{source}}, Unset) else (None, str({{source}}).encode(), "text/plain") -{% else %} -{{ destination }} = (None, str({{ source }}).encode(), "text/plain") -{%- endif -%} +{% macro multipart(property, source, destination) %} +field_list.append(({{ destination }}, (None, str({{source}}).encode(), "text/plain"))) {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/int_property.py.jinja b/openapi_python_client/templates/property_templates/int_property.py.jinja index 12ffb0fb4..0729c82fb 100644 --- a/openapi_python_client/templates/property_templates/int_property.py.jinja +++ b/openapi_python_client/templates/property_templates/int_property.py.jinja @@ -2,10 +2,6 @@ str({{ source }}) {% endmacro %} -{% macro transform_multipart(property, source, destination) %} -{% if not property.required %} -{{ destination }} = {{source}} if isinstance({{source}}, Unset) else (None, str({{source}}).encode(), "text/plain") -{% else %} -{{ destination }} = (None, str({{ source }}).encode(), "text/plain") -{% endif %} +{% macro multipart(property, source, destination) %} +field_list.append(({{ destination }}, (None, str({{source}}).encode(), "text/plain"))) {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/list_property.py.jinja b/openapi_python_client/templates/property_templates/list_property.py.jinja index 94a9c6d65..fc68cb2ec 100644 --- a/openapi_python_client/templates/property_templates/list_property.py.jinja +++ b/openapi_python_client/templates/property_templates/list_property.py.jinja @@ -17,12 +17,8 @@ for {{ inner_source }} in (_{{ property.python_name }} or []): {% endif %} {% endmacro %} -{% macro _transform(property, source, destination, multipart, transform_method) %} +{% macro _transform(property, source, destination, transform_method) %} {% set inner_property = property.inner_property %} -{% if multipart %} -{% set multipart_destination = destination %} -{% set destination = "_temp_" + destination %} -{% endif %} {% import "property_templates/" + inner_property.template as inner_template %} {% if inner_template.transform %} {% set inner_source = inner_property.python_name + "_data" %} @@ -33,9 +29,6 @@ for {{ inner_source }} in {{ source }}: {% else %} {{ destination }} = {{ source }} {% endif %} -{% if multipart %} -{{ multipart_destination }} = (None, json.dumps({{ destination }}).encode(), 'application/json') -{% endif %} {% endmacro %} {% macro check_type_for_construct(property, source) %}isinstance({{ source }}, list){% endmacro %} @@ -44,34 +37,30 @@ for {{ inner_source }} in {{ source }}: {% set inner_property = property.inner_property %} {% set type_string = property.get_type_string(json=True) %} {% if property.required %} -{{ _transform(property, source, destination, False, "to_dict") }} +{{ _transform(property, source, destination, "to_dict") }} {% else %} {{ destination }}{% if declare_type %}: {{ type_string }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): - {{ _transform(property, source, destination, False, "to_dict") | indent(4)}} + {{ _transform(property, source, destination, "to_dict") | indent(4)}} {% endif %} {% endmacro %} -{% macro transform_multipart(property, source, destination) %} +{% macro transform_multipart_body(property, source, destination) %} {% set inner_property = property.inner_property %} -{% set type_string = "Union[Unset, tuple[None, bytes, str]]" %} +{% set type_string = property.get_type_string(json=True) %} {% if property.required %} -{{ _transform(property, source, destination, True, "to_dict") }} +{{ _transform(property, source, destination, "to_multipart") }} {% else %} {{ destination }}: {{ type_string }} = UNSET if not isinstance({{ source }}, Unset): - {{ _transform(property, source, destination, True, "to_dict") | indent(4)}} + {{ _transform(property, source, destination, "to_multipart") | indent(4)}} {% endif %} {% endmacro %} -{% macro transform_multipart_body(property, source, destination) %} +{% macro multipart(property, source, destination) %} {% set inner_property = property.inner_property %} -{% set type_string = property.get_type_string(json=True) %} -{% if property.required %} -{{ _transform(property, source, destination, False, "to_multipart") }} -{% else %} -{{ destination }}: {{ type_string }} = UNSET -if not isinstance({{ source }}, Unset): - {{ _transform(property, source, destination, False, "to_multipart") | indent(4)}} -{% endif %} +{% import "property_templates/" + inner_property.template as inner_template %} +{% set inner_source = inner_property.python_name + "_element" %} +for {{ inner_source }} in {{ source }}: + {{ inner_template.multipart(inner_property, inner_source, destination) | indent(4) }} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/literal_enum_property.py.jinja b/openapi_python_client/templates/property_templates/literal_enum_property.py.jinja index 1506284d7..442d102ea 100644 --- a/openapi_python_client/templates/property_templates/literal_enum_property.py.jinja +++ b/openapi_python_client/templates/property_templates/literal_enum_property.py.jinja @@ -21,16 +21,9 @@ if not isinstance({{ source }}, Unset): {% endif %} {% endmacro %} -{% macro transform_multipart(property, source, destination) %} +{% macro multipart(property, source, destination) %} {% set transformed = "(None, str(" + source + ").encode(), \"text/plain\")" %} -{% set type_string = "Union[Unset, tuple[None, bytes, str]]" %} -{% if property.required %} -{{ destination }} = {{ transformed }} -{%- else %} -{{ destination }}: {{ type_string }} = UNSET -if not isinstance({{ source }}, Unset): - {{ destination }} = {{ transformed }} -{% endif %} +field_list.append(({{ destination }}, {{ transformed }})) {% endmacro %} {% macro transform_header(source) %} diff --git a/openapi_python_client/templates/property_templates/model_property.py.jinja b/openapi_python_client/templates/property_templates/model_property.py.jinja index 308b7478b..fbc517b43 100644 --- a/openapi_python_client/templates/property_templates/model_property.py.jinja +++ b/openapi_python_client/templates/property_templates/model_property.py.jinja @@ -34,14 +34,7 @@ if not isinstance({{ source }}, Unset): {%- endif %} {% endmacro %} -{% macro transform_multipart(property, source, destination) %} +{% macro multipart(property, source, destination) %} {% set transformed = "(None, json.dumps(" + source + ".to_dict()" + ").encode(), 'application/json')" %} -{% set type_string = property.get_type_string(multipart=True) %} -{% if property.required %} -{{ destination }} = {{ transformed }} -{%- else %} -{{ destination }}: {{ type_string }} = UNSET -if not isinstance({{ source }}, Unset): - {{ destination }} = {{ transformed }} -{%- endif %} +field_list.append(({{ destination }}, {{ transformed }})) {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/union_property.py.jinja b/openapi_python_client/templates/property_templates/union_property.py.jinja index b39e2d5cc..5f76702f9 100644 --- a/openapi_python_client/templates/property_templates/union_property.py.jinja +++ b/openapi_python_client/templates/property_templates/union_property.py.jinja @@ -83,14 +83,8 @@ if isinstance({{ source }}, {{ inner_property.get_instance_type_string() }}): {% endif %} {% endmacro %} -{% macro transform_multipart(property, source, destination) %} +{% macro multipart(property, source, destination) %} {% set ns = namespace(has_if = false) %} -{{ destination }}: {{ property.get_type_string(json=False, multipart=True) }} -{% if not property.required %} -if isinstance({{ source }}, Unset): - {{ destination }} = UNSET - {% set ns.has_if = true %} -{% endif %} {% for inner_property in property.inner_properties %} {% if not ns.has_if %} {{ instance_check(inner_property, source) }} @@ -103,6 +97,6 @@ el{{ instance_check(inner_property, source) }} else: {% endif %} {% import "property_templates/" + inner_property.template as inner_template %} - {{ inner_template.transform_multipart(inner_property, source, destination) | indent(4) | trim }} + {{ inner_template.multipart(inner_property, source, destination) | indent(4) | trim }} {%- endfor -%} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/uuid_property.py.jinja b/openapi_python_client/templates/property_templates/uuid_property.py.jinja index 1f91c1e3a..922cf0f89 100644 --- a/openapi_python_client/templates/property_templates/uuid_property.py.jinja +++ b/openapi_python_client/templates/property_templates/uuid_property.py.jinja @@ -26,13 +26,6 @@ if not isinstance({{ source }}, Unset): {%- endif %} {% endmacro %} -{% macro transform_multipart(property, source, destination) %} -{% if property.required %} -{{ destination }} = str({{ source }}) -{%- else %} -{% set type_annotation = property.get_type_string(json=True) | replace("str", "bytes") %} -{{ destination }}: {{ type_annotation }} = UNSET -if not isinstance({{ source }}, Unset): - {{ destination }} = str({{ source }}) -{%- endif %} +{% macro multipart(property, source, destination) %} +field_list.append(({{ destination }},str({{ source }}))) {% endmacro %}