Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
changeKind: fix
packages:
- "@autorest/python"
- "@azure-tools/typespec-python"
---

Fix multipart when files part is optional
2 changes: 1 addition & 1 deletion packages/autorest.python/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"homepage": "https://github.com/Azure/autorest.python/blob/main/README.md",
"dependencies": {
"@typespec/http-client-python": "https://artprodcus3.artifacts.visualstudio.com/A0fb41ef4-5012-48a9-bf39-4ee3de03ee35/29ec6040-b234-4e31-b139-33dc4287b756/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2F6dXJlLXNkay9wcm9qZWN0SWQvMjllYzYwNDAtYjIzNC00ZTMxLWIxMzktMzNkYzQyODdiNzU2L2J1aWxkSWQvNTY0MTUwOC9hcnRpZmFjdE5hbWUvYnVpbGRfYXJ0aWZhY3RzX3B5dGhvbg2/content?format=file&subPath=%2Fpackages%2Ftypespec-http-client-python-0.21.0.tgz",
"@typespec/http-client-python": "https://artprodcus3.artifacts.visualstudio.com/A0fb41ef4-5012-48a9-bf39-4ee3de03ee35/29ec6040-b234-4e31-b139-33dc4287b756/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2F6dXJlLXNkay9wcm9qZWN0SWQvMjllYzYwNDAtYjIzNC00ZTMxLWIxMzktMzNkYzQyODdiNzU2L2J1aWxkSWQvNTY0NjEzMi9hcnRpZmFjdE5hbWUvYnVpbGRfYXJ0aWZhY3RzX3B5dGhvbg2/content?format=file&subPath=%2Fpackages%2Ftypespec-http-client-python-0.21.0.tgz",
"@autorest/system-requirements": "~1.0.2",
"fs-extra": "~11.2.0",
"tsx": "~4.19.1"
Expand Down
2 changes: 1 addition & 1 deletion packages/typespec-python/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"js-yaml": "~4.1.0",
"semver": "~7.6.2",
"tsx": "~4.19.1",
"@typespec/http-client-python": "https://artprodcus3.artifacts.visualstudio.com/A0fb41ef4-5012-48a9-bf39-4ee3de03ee35/29ec6040-b234-4e31-b139-33dc4287b756/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2F6dXJlLXNkay9wcm9qZWN0SWQvMjllYzYwNDAtYjIzNC00ZTMxLWIxMzktMzNkYzQyODdiNzU2L2J1aWxkSWQvNTY0MTUwOC9hcnRpZmFjdE5hbWUvYnVpbGRfYXJ0aWZhY3RzX3B5dGhvbg2/content?format=file&subPath=%2Fpackages%2Ftypespec-http-client-python-0.21.0.tgz",
"@typespec/http-client-python": "https://artprodcus3.artifacts.visualstudio.com/A0fb41ef4-5012-48a9-bf39-4ee3de03ee35/29ec6040-b234-4e31-b139-33dc4287b756/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2F6dXJlLXNkay9wcm9qZWN0SWQvMjllYzYwNDAtYjIzNC00ZTMxLWIxMzktMzNkYzQyODdiNzU2L2J1aWxkSWQvNTY0NjEzMi9hcnRpZmFjdE5hbWUvYnVpbGRfYXJ0aWZhY3RzX3B5dGhvbg2/content?format=file&subPath=%2Fpackages%2Ftypespec-http-client-python-0.21.0.tgz",
"fs-extra": "~11.2.0"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,20 @@ def serialize_multipart_data_entry(data_entry: Any) -> Any:

def prepare_multipart_form_data(
body: Mapping[str, Any], multipart_fields: list[str], data_fields: list[str]
) -> tuple[list[FileType], dict[str, Any]]:
) -> list[FileType]:
files: list[FileType] = []
data: dict[str, Any] = {}
for multipart_field in multipart_fields:
multipart_entry = body.get(multipart_field)
if isinstance(multipart_entry, list):
files.extend([(multipart_field, e) for e in multipart_entry])
elif multipart_entry:
files.append((multipart_field, multipart_entry))

# if files is empty, sdk core library can't handle multipart/form-data correctly, so
# we put data fields into files with filename as None to avoid that scenario.
for data_field in data_fields:
data_entry = body.get(data_field)
if data_entry:
data[data_field] = serialize_multipart_data_entry(data_entry)
files.append((data_field, str(serialize_multipart_data_entry(data_entry))))

return files, data
return files
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,10 @@ async def basic(self, body: Union[_models.MultiPartRequest, JSON], **kwargs: Any
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = ["id"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_basic_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -189,11 +188,10 @@ async def file_array_and_basic(self, body: Union[_models.ComplexPartsRequest, JS
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage", "pictures"]
_data_fields: list[str] = ["id", "address"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_file_array_and_basic_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -264,11 +262,10 @@ async def json_part(self, body: Union[_models.JsonPartRequest, JSON], **kwargs:
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = ["address"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_json_part_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -339,11 +336,10 @@ async def binary_array_parts(self, body: Union[_models.BinaryArrayPartsRequest,
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["pictures"]
_data_fields: list[str] = ["id"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_binary_array_parts_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -414,11 +410,10 @@ async def multi_binary_parts(self, body: Union[_models.MultiBinaryPartsRequest,
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage", "picture"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_multi_binary_parts_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -491,11 +486,10 @@ async def check_file_name_and_content_type(
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = ["id"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_check_file_name_and_content_type_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -566,11 +560,10 @@ async def anonymous_model(self, body: Union[_models.AnonymousModelRequest, JSON]
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_anonymous_model_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -668,11 +661,10 @@ async def json_array_and_file_array(
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage", "pictures"]
_data_fields: list[str] = ["id", "address", "previousAddresses"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_json_array_and_file_array_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -766,11 +758,10 @@ async def image_jpeg_content_type(
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_content_type_image_jpeg_content_type_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -846,11 +837,10 @@ async def required_content_type(
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_content_type_required_content_type_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -926,11 +916,10 @@ async def optional_content_type(
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_content_type_optional_content_type_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -1019,11 +1008,10 @@ async def float(self, body: Union[_models.FloatRequest, JSON], **kwargs: Any) ->
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = []
_data_fields: list[str] = ["temperature"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_non_string_float_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,10 @@ def basic( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = ["id"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_basic_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -301,11 +300,10 @@ def file_array_and_basic( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage", "pictures"]
_data_fields: list[str] = ["id", "address"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_file_array_and_basic_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -378,11 +376,10 @@ def json_part( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = ["address"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_json_part_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -455,11 +452,10 @@ def binary_array_parts( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["pictures"]
_data_fields: list[str] = ["id"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_binary_array_parts_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -532,11 +528,10 @@ def multi_binary_parts( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage", "picture"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_multi_binary_parts_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -609,11 +604,10 @@ def check_file_name_and_content_type( # pylint: disable=inconsistent-return-sta
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = ["id"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_check_file_name_and_content_type_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -686,11 +680,10 @@ def anonymous_model( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_anonymous_model_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -788,11 +781,10 @@ def json_array_and_file_array( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage", "pictures"]
_data_fields: list[str] = ["id", "address", "previousAddresses"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_json_array_and_file_array_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -884,11 +876,10 @@ def image_jpeg_content_type( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_content_type_image_jpeg_content_type_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -962,11 +953,10 @@ def required_content_type( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_content_type_required_content_type_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -1040,11 +1030,10 @@ def optional_content_type( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = ["profileImage"]
_data_fields: list[str] = []
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_content_type_optional_content_type_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down Expand Up @@ -1135,11 +1124,10 @@ def float( # pylint: disable=inconsistent-return-statements
_body = body.as_dict() if isinstance(body, _Model) else body
_file_fields: list[str] = []
_data_fields: list[str] = ["temperature"]
_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)
_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)

_request = build_form_data_http_parts_non_string_float_request(
files=_files,
data=_data,
headers=_headers,
params=_params,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ def serialize_multipart_data_entry(data_entry: Any) -> Any:

def prepare_multipart_form_data(
body: Mapping[str, Any], multipart_fields: list[str], data_fields: list[str]
) -> tuple[list[FileType], dict[str, Any]]:
) -> list[FileType]:
files: list[FileType] = []
data: dict[str, Any] = {}
for multipart_field in multipart_fields:
multipart_entry = body.get(multipart_field)
if isinstance(multipart_entry, list):
files.extend([(multipart_field, e) for e in multipart_entry])
elif multipart_entry:
files.append((multipart_field, multipart_entry))

# if files is empty, sdk core library can't handle multipart/form-data correctly, so
# we put data fields into files with filename as None to avoid that scenario.
for data_field in data_fields:
data_entry = body.get(data_field)
if data_entry:
data[data_field] = serialize_multipart_data_entry(data_entry)
files.append((data_field, str(serialize_multipart_data_entry(data_entry))))

return files, data
return files
Loading
Loading