diff --git a/.changeset/always_use_correct_content_type_for_requests.md b/.changeset/always_use_correct_content_type_for_requests.md new file mode 100644 index 000000000..bb4ff4f0b --- /dev/null +++ b/.changeset/always_use_correct_content_type_for_requests.md @@ -0,0 +1,9 @@ +--- +default: patch +--- + +# Always use correct content type for requests + +In previous versions, a request body that was similar to a known content type would use that content type in the request. For example `application/json` would be used for `application/vnd.api+json`. This was incorrect and could result in invalid requests being sent. + +Now, the content type defined in the OpenAPI document will always be used. diff --git a/.changeset/renamed_body_types_and_parameters.md b/.changeset/renamed_body_types_and_parameters.md new file mode 100644 index 000000000..7ab407cb7 --- /dev/null +++ b/.changeset/renamed_body_types_and_parameters.md @@ -0,0 +1,29 @@ +--- +default: major +--- + +# Renamed body types and parameters + +PR #900 addresses #822. + +Where previously there would be one body parameter per supported content type, now there is a single `body` parameter which takes a union of all the possible inputs. This correctly models the fact that only one body can be sent (and ever would be sent) in a request. + +For example, when calling a generated endpoint, code which used to look like this: + +```python +post_body_multipart.sync_detailed( + client=client, + multipart_data=PostBodyMultipartMultipartData(), +) +``` + +Will now look like this: + +```python +post_body_multipart.sync_detailed( + client=client, + body=PostBodyMultipartBody(), +) +``` + +Note that both the input parameter name _and_ the class name have changed. This should result in simpler code when there is only a single body type and now produces correct code when there are multiple body types. diff --git a/.changeset/support_multiple_possible_requestbody.md b/.changeset/support_multiple_possible_requestbody.md new file mode 100644 index 000000000..446374d16 --- /dev/null +++ b/.changeset/support_multiple_possible_requestbody.md @@ -0,0 +1,16 @@ +--- +default: minor +--- + +# Support multiple possible `requestBody` + +PR #900 addresses #822. + +It is now possible in some circumstances to generate valid code for OpenAPI documents which have multiple possible `requestBody` values. Previously, invalid code could have been generated with no warning (only one body could actually be sent). + +Only one content type per "category" is currently supported at a time. The categories are: + +- JSON, like `application/json` +- Binary data, like `application/octet-stream` +- Encoded form data, like `application/x-www-form-urlencoded` +- Files, like `multipart/form-data` diff --git a/end_to_end_tests/baseline_openapi_3.0.json b/end_to_end_tests/baseline_openapi_3.0.json index 14493030f..d21d1d57f 100644 --- a/end_to_end_tests/baseline_openapi_3.0.json +++ b/end_to_end_tests/baseline_openapi_3.0.json @@ -6,6 +6,85 @@ "version": "0.1.0" }, "paths": { + "/bodies/multiple": { + "post": { + "description": "Test multiple bodies", + "tags": [ + "bodies" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + } + } + } + }, + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + } + } + } + }, + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/bodies/json-like": { + "post": { + "tags": ["bodies"], + "description": "A content type that works like json but isn't application/json", + "operationId": "json-like", + "requestBody": { + "content": { + "application/vnd+json": { + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/tests/": { "get": { "tags": [ @@ -806,7 +885,9 @@ }, "/responses/unions/simple_before_complex": { "post": { - "tags": ["responses"], + "tags": [ + "responses" + ], "description": "Regression test for #603", "responses": { "200": { @@ -815,12 +896,18 @@ "application/json": { "schema": { "type": "object", - "required": ["a"], + "required": [ + "a" + ], "properties": { "a": { "oneOf": [ - {"type": "string"}, - {"type": "object"} + { + "type": "string" + }, + { + "type": "object" + } ] } } @@ -948,20 +1035,20 @@ }, "parameters": [ { - "name": "param", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "param", - "in": "path", - "required": true, - "schema": { - "type": "string" - } + "name": "param", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "param", + "in": "path", + "required": true, + "schema": { + "type": "string" } + } ] }, "/same-name-multiple-locations/{param}": { @@ -1010,7 +1097,9 @@ }, "/tag_with_number": { "get": { - "tags": ["1"], + "tags": [ + "1" + ], "responses": { "200": { "description": "Success" @@ -1253,7 +1342,9 @@ "/naming/property-conflict-with-import": { "description": "Ensure that property names don't conflict with imports", "post": { - "tags": ["naming"], + "tags": [ + "naming" + ], "requestBody": { "content": { "application/json": { @@ -1310,9 +1401,15 @@ { "$ref": "#/components/parameters/integer-param" }, - {"$ref": "#/components/parameters/header-param"}, - {"$ref": "#/components/parameters/cookie-param"}, - {"$ref": "#/components/parameters/path-param"} + { + "$ref": "#/components/parameters/header-param" + }, + { + "$ref": "#/components/parameters/cookie-param" + }, + { + "$ref": "#/components/parameters/path-param" + } ], "responses": { "200": { @@ -1643,7 +1740,11 @@ }, "Body_upload_file_tests_upload_post": { "title": "Body_upload_file_tests_upload_post", - "required": ["some_file", "some_object", "some_nullable_object"], + "required": [ + "some_file", + "some_object", + "some_nullable_object" + ], "type": "object", "properties": { "some_file": { @@ -1685,7 +1786,10 @@ "some_object": { "title": "Some Object", "type": "object", - "required": ["num", "text"], + "required": [ + "num", + "text" + ], "properties": { "num": { "type": "number" @@ -1698,7 +1802,9 @@ "some_optional_object": { "title": "Some Optional Object", "type": "object", - "required": ["foo"], + "required": [ + "foo" + ], "properties": { "foo": { "type": "string" @@ -1921,7 +2027,10 @@ }, "type_enum": { "type": "integer", - "enum": [0, 1] + "enum": [ + 0, + 1 + ] } } }, @@ -1934,11 +2043,15 @@ }, "type": { "type": "string", - "enum": ["submodel"] + "enum": [ + "submodel" + ] }, "type_enum": { "type": "integer", - "enum": [0] + "enum": [ + 0 + ] } } }, @@ -1953,7 +2066,10 @@ }, "type_enum": { "type": "integer", - "enum": [0, 1] + "enum": [ + 0, + 1 + ] } } }, @@ -2096,7 +2212,7 @@ } } }, - "ModelWithDateTimeProperty" : { + "ModelWithDateTimeProperty": { "type": "object", "properties": { "datetime": { @@ -2274,10 +2390,10 @@ "type": "string", "format": "byte" }, - "import": { + "import": { "type": "object" }, - "None": { + "None": { "type": "object" }, "model.reference.with.Periods": { diff --git a/end_to_end_tests/baseline_openapi_3.1.yaml b/end_to_end_tests/baseline_openapi_3.1.yaml index 2d1c1f9ac..03270af6b 100644 --- a/end_to_end_tests/baseline_openapi_3.1.yaml +++ b/end_to_end_tests/baseline_openapi_3.1.yaml @@ -4,6 +4,85 @@ info: description: "An API for testing openapi-python-client" version: "0.1.0" "paths": { + "/bodies/multiple": { + "post": { + "description": "Test multiple bodies", + "tags": [ + "bodies" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + } + } + } + }, + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + } + } + } + }, + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/bodies/json-like": { + "post": { + "tags": [ "bodies" ], + "description": "A content type that works like json but isn't application/json", + "operationId": "json-like", + "requestBody": { + "content": { + "application/vnd+json": { + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/tests/": { "get": { "tags": [ @@ -537,8 +616,8 @@ info: "schema": { "title": "Union Prop", "type": [ - "number", - "string" + "number", + "string" ], "default": "not a float" }, diff --git a/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/__init__.py b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/__init__.py index 80575f2aa..3cc02b59a 100644 --- a/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/__init__.py +++ b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/__init__.py @@ -2,6 +2,7 @@ from typing import Type +from .bodies import BodiesEndpoints from .default import DefaultEndpoints from .defaults import DefaultsEndpoints from .location import LocationEndpoints @@ -15,6 +16,10 @@ class MyTestApiClientApi: + @classmethod + def bodies(cls) -> Type[BodiesEndpoints]: + return BodiesEndpoints + @classmethod def tests(cls) -> Type[TestsEndpoints]: return TestsEndpoints diff --git a/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/bodies/__init__.py b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/bodies/__init__.py new file mode 100644 index 000000000..ffbb41025 --- /dev/null +++ b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/bodies/__init__.py @@ -0,0 +1,21 @@ +""" Contains methods for accessing the API Endpoints """ + +import types + +from . import json_like, post_bodies_multiple + + +class BodiesEndpoints: + @classmethod + def post_bodies_multiple(cls) -> types.ModuleType: + """ + Test multiple bodies + """ + return post_bodies_multiple + + @classmethod + def json_like(cls) -> types.ModuleType: + """ + A content type that works like json but isn't application/json + """ + return json_like diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/bodies/__init__.py b/end_to_end_tests/golden-record/my_test_api_client/api/bodies/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/bodies/json_like.py b/end_to_end_tests/golden-record/my_test_api_client/api/bodies/json_like.py new file mode 100644 index 000000000..8eb5c516a --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/api/bodies/json_like.py @@ -0,0 +1,103 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.json_like_body import JsonLikeBody +from ...types import Response + + +def _get_kwargs( + *, + body: JsonLikeBody, +) -> Dict[str, Any]: + headers: Dict[str, Any] = {} + + _kwargs: Dict[str, Any] = { + "method": "post", + "url": "/bodies/json-like", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/vnd+json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == HTTPStatus.OK: + return None + 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[Any]: + 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: JsonLikeBody, +) -> Response[Any]: + """A content type that works like json but isn't application/json + + Args: + body (JsonLikeBody): + + 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[Any] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: JsonLikeBody, +) -> Response[Any]: + """A content type that works like json but isn't application/json + + Args: + body (JsonLikeBody): + + 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[Any] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/bodies/post_bodies_multiple.py b/end_to_end_tests/golden-record/my_test_api_client/api/bodies/post_bodies_multiple.py new file mode 100644 index 000000000..f71b1ef25 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/api/bodies/post_bodies_multiple.py @@ -0,0 +1,142 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.post_bodies_multiple_data_body import PostBodiesMultipleDataBody +from ...models.post_bodies_multiple_files_body import PostBodiesMultipleFilesBody +from ...models.post_bodies_multiple_json_body import PostBodiesMultipleJsonBody +from ...types import File, Response + + +def _get_kwargs( + *, + body: Union[ + PostBodiesMultipleJsonBody, + File, + PostBodiesMultipleDataBody, + PostBodiesMultipleFilesBody, + ], +) -> Dict[str, Any]: + headers: Dict[str, Any] = {} + + _kwargs: Dict[str, Any] = { + "method": "post", + "url": "/bodies/multiple", + } + + if isinstance(body, PostBodiesMultipleJsonBody): + _json_body = body.to_dict() + + _kwargs["json"] = _json_body + headers["Content-Type"] = "application/json" + if isinstance(body, File): + _content_body = body.payload + + _kwargs["content"] = _content_body + headers["Content-Type"] = "application/octet-stream" + if isinstance(body, PostBodiesMultipleDataBody): + _data_body = body.to_dict() + + _kwargs["data"] = _data_body + headers["Content-Type"] = "application/x-www-form-urlencoded" + if isinstance(body, PostBodiesMultipleFilesBody): + _files_body = body.to_multipart() + + _kwargs["files"] = _files_body + headers["Content-Type"] = "multipart/form-data" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == HTTPStatus.OK: + return None + 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[Any]: + 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: Union[ + PostBodiesMultipleJsonBody, + File, + PostBodiesMultipleDataBody, + PostBodiesMultipleFilesBody, + ], +) -> Response[Any]: + """Test multiple bodies + + Args: + body (PostBodiesMultipleJsonBody): + body (File): + body (PostBodiesMultipleDataBody): + body (PostBodiesMultipleFilesBody): + + 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[Any] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: Union[ + PostBodiesMultipleJsonBody, + File, + PostBodiesMultipleDataBody, + PostBodiesMultipleFilesBody, + ], +) -> Response[Any]: + """Test multiple bodies + + Args: + body (PostBodiesMultipleJsonBody): + body (File): + body (PostBodiesMultipleDataBody): + body (PostBodiesMultipleFilesBody): + + 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[Any] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/default/get_common_parameters.py b/end_to_end_tests/golden-record/my_test_api_client/api/default/get_common_parameters.py index 1c02c81d2..f782162b1 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/default/get_common_parameters.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/default/get_common_parameters.py @@ -18,12 +18,14 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/common_parameters", "params": params, } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/default/post_common_parameters.py b/end_to_end_tests/golden-record/my_test_api_client/api/default/post_common_parameters.py index 0c3b351f3..6cfc13bd4 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/default/post_common_parameters.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/default/post_common_parameters.py @@ -18,12 +18,14 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/common_parameters", "params": params, } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/default/reserved_parameters.py b/end_to_end_tests/golden-record/my_test_api_client/api/default/reserved_parameters.py index 8f436901f..9033321c7 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/default/reserved_parameters.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/default/reserved_parameters.py @@ -21,12 +21,14 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/naming/reserved-parameters", "params": params, } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/defaults/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/defaults/defaults_tests_defaults_post.py index 529190562..02f5b6ff7 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/defaults/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/defaults/defaults_tests_defaults_post.py @@ -77,12 +77,14 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/defaults", "params": params, } + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_header_types.py b/end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_header_types.py index b004866ce..904d26c72 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_header_types.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_header_types.py @@ -19,7 +19,7 @@ def _get_kwargs( int_enum_header: Union[Unset, GetLocationHeaderTypesIntEnumHeader] = UNSET, string_enum_header: Union[Unset, GetLocationHeaderTypesStringEnumHeader] = UNSET, ) -> Dict[str, Any]: - headers = {} + headers: Dict[str, Any] = {} if not isinstance(boolean_header, Unset): headers["Boolean-Header"] = "true" if boolean_header else "false" @@ -38,12 +38,14 @@ def _get_kwargs( if not isinstance(string_enum_header, Unset): headers["String-Enum-Header"] = str(string_enum_header) - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/location/header/types", - "headers": headers, } + _kwargs["headers"] = headers + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_query_optionality.py b/end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_query_optionality.py index 9bacd49e5..c50642749 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_query_optionality.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_query_optionality.py @@ -46,12 +46,14 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/location/query/optionality", "params": params, } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/naming/post_naming_property_conflict_with_import.py b/end_to_end_tests/golden-record/my_test_api_client/api/naming/post_naming_property_conflict_with_import.py index 6174aea46..693eab608 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/naming/post_naming_property_conflict_with_import.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/naming/post_naming_property_conflict_with_import.py @@ -5,7 +5,7 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.post_naming_property_conflict_with_import_json_body import PostNamingPropertyConflictWithImportJsonBody +from ...models.post_naming_property_conflict_with_import_body import PostNamingPropertyConflictWithImportBody from ...models.post_naming_property_conflict_with_import_response_200 import ( PostNamingPropertyConflictWithImportResponse200, ) @@ -14,16 +14,23 @@ def _get_kwargs( *, - json_body: PostNamingPropertyConflictWithImportJsonBody, + body: PostNamingPropertyConflictWithImportBody, ) -> Dict[str, Any]: - json_json_body = json_body.to_dict() + headers: Dict[str, Any] = {} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/naming/property-conflict-with-import", - "json": json_json_body, } + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -52,11 +59,11 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: PostNamingPropertyConflictWithImportJsonBody, + body: PostNamingPropertyConflictWithImportBody, ) -> Response[PostNamingPropertyConflictWithImportResponse200]: """ Args: - json_body (PostNamingPropertyConflictWithImportJsonBody): + body (PostNamingPropertyConflictWithImportBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -67,7 +74,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = client.get_httpx_client().request( @@ -80,11 +87,11 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], - json_body: PostNamingPropertyConflictWithImportJsonBody, + body: PostNamingPropertyConflictWithImportBody, ) -> Optional[PostNamingPropertyConflictWithImportResponse200]: """ Args: - json_body (PostNamingPropertyConflictWithImportJsonBody): + body (PostNamingPropertyConflictWithImportBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -96,18 +103,18 @@ def sync( return sync_detailed( client=client, - json_body=json_body, + body=body, ).parsed async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: PostNamingPropertyConflictWithImportJsonBody, + body: PostNamingPropertyConflictWithImportBody, ) -> Response[PostNamingPropertyConflictWithImportResponse200]: """ Args: - json_body (PostNamingPropertyConflictWithImportJsonBody): + body (PostNamingPropertyConflictWithImportBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -118,7 +125,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -129,11 +136,11 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], - json_body: PostNamingPropertyConflictWithImportJsonBody, + body: PostNamingPropertyConflictWithImportBody, ) -> Optional[PostNamingPropertyConflictWithImportResponse200]: """ Args: - json_body (PostNamingPropertyConflictWithImportJsonBody): + body (PostNamingPropertyConflictWithImportBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -146,6 +153,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, - json_body=json_body, + body=body, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/parameter_references/get_parameter_references_path_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/parameter_references/get_parameter_references_path_param.py index aca8f6858..861a50749 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/parameter_references/get_parameter_references_path_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/parameter_references/get_parameter_references_path_param.py @@ -16,7 +16,7 @@ def _get_kwargs( header_param: Union[None, Unset, str] = UNSET, cookie_param: Union[Unset, str] = UNSET, ) -> Dict[str, Any]: - headers = {} + headers: Dict[str, Any] = {} if not isinstance(header_param, Unset): headers["header param"] = header_param @@ -32,16 +32,18 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/parameter-references/{path_param}".format( path_param=path_param, ), "params": params, - "headers": headers, "cookies": cookies, } + _kwargs["headers"] = headers + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/parameters/delete_common_parameters_overriding_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/parameters/delete_common_parameters_overriding_param.py index c0ea3b0cb..693044930 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/parameters/delete_common_parameters_overriding_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/parameters/delete_common_parameters_overriding_param.py @@ -19,7 +19,7 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "delete", "url": "/common_parameters_overriding/{param}".format( param=param_path, @@ -27,6 +27,8 @@ def _get_kwargs( "params": params, } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/parameters/get_common_parameters_overriding_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/parameters/get_common_parameters_overriding_param.py index c3074476a..6f29152a2 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/parameters/get_common_parameters_overriding_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/parameters/get_common_parameters_overriding_param.py @@ -19,7 +19,7 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/common_parameters_overriding/{param}".format( param=param_path, @@ -27,6 +27,8 @@ def _get_kwargs( "params": params, } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/parameters/get_same_name_multiple_locations_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/parameters/get_same_name_multiple_locations_param.py index aad28a5f2..e4453277a 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/parameters/get_same_name_multiple_locations_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/parameters/get_same_name_multiple_locations_param.py @@ -15,7 +15,7 @@ def _get_kwargs( param_header: Union[Unset, str] = UNSET, param_cookie: Union[Unset, str] = UNSET, ) -> Dict[str, Any]: - headers = {} + headers: Dict[str, Any] = {} if not isinstance(param_header, Unset): headers["param"] = param_header @@ -29,16 +29,18 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/same-name-multiple-locations/{param}".format( param=param_path, ), "params": params, - "headers": headers, "cookies": cookies, } + _kwargs["headers"] = headers + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/parameters/multiple_path_parameters.py b/end_to_end_tests/golden-record/my_test_api_client/api/parameters/multiple_path_parameters.py index 0e8ce7ec5..6ffacceb7 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/parameters/multiple_path_parameters.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/parameters/multiple_path_parameters.py @@ -14,7 +14,7 @@ def _get_kwargs( param1: str, param3: int, ) -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/multiple-path-parameters/{param4}/something/{param2}/{param1}/{param3}".format( param4=param4, @@ -24,6 +24,8 @@ def _get_kwargs( ), } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/responses/post_responses_unions_simple_before_complex.py b/end_to_end_tests/golden-record/my_test_api_client/api/responses/post_responses_unions_simple_before_complex.py index 3bb13d534..63f551edc 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/responses/post_responses_unions_simple_before_complex.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/responses/post_responses_unions_simple_before_complex.py @@ -12,11 +12,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/responses/unions/simple_before_complex", } + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/responses/text_response.py b/end_to_end_tests/golden-record/my_test_api_client/api/responses/text_response.py index ce3f87e78..c7d71a3f3 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/responses/text_response.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/responses/text_response.py @@ -9,11 +9,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/responses/text", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[str]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tag1/get_tag_with_number.py b/end_to_end_tests/golden-record/my_test_api_client/api/tag1/get_tag_with_number.py index c2bacd545..eedbd5f7a 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tag1/get_tag_with_number.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tag1/get_tag_with_number.py @@ -9,11 +9,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tag_with_number", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/callback_test.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/callback_test.py index 643e9c0f6..925349cbd 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/callback_test.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/callback_test.py @@ -12,16 +12,23 @@ def _get_kwargs( *, - json_body: AModel, + body: AModel, ) -> Dict[str, Any]: - json_json_body = json_body.to_dict() + headers: Dict[str, Any] = {} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/callback", - "json": json_json_body, } + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -53,14 +60,14 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: AModel, + body: AModel, ) -> Response[Union[Any, HTTPValidationError]]: """Path with callback Try sending a request related to a callback Args: - json_body (AModel): A Model for testing all the ways custom objects can be used + body (AModel): A Model for testing all the ways custom objects can be used Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -71,7 +78,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = client.get_httpx_client().request( @@ -84,14 +91,14 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], - json_body: AModel, + body: AModel, ) -> Optional[Union[Any, HTTPValidationError]]: """Path with callback Try sending a request related to a callback Args: - json_body (AModel): A Model for testing all the ways custom objects can be used + body (AModel): A Model for testing all the ways custom objects can be used Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -103,21 +110,21 @@ def sync( return sync_detailed( client=client, - json_body=json_body, + body=body, ).parsed async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: AModel, + body: AModel, ) -> Response[Union[Any, HTTPValidationError]]: """Path with callback Try sending a request related to a callback Args: - json_body (AModel): A Model for testing all the ways custom objects can be used + body (AModel): A Model for testing all the ways custom objects can be used Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -128,7 +135,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -139,14 +146,14 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], - json_body: AModel, + body: AModel, ) -> Optional[Union[Any, HTTPValidationError]]: """Path with callback Try sending a request related to a callback Args: - json_body (AModel): A Model for testing all the ways custom objects can be used + body (AModel): A Model for testing all the ways custom objects can be used Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -159,6 +166,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, - json_body=json_body, + body=body, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/description_with_backslash.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/description_with_backslash.py index 20954b5d7..9ddd267d8 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/description_with_backslash.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/description_with_backslash.py @@ -9,11 +9,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tests/description-with-backslash", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_booleans.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_booleans.py index 73a08b31a..8f90e7eb6 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_booleans.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_booleans.py @@ -9,11 +9,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tests/basic_lists/booleans", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[List[bool]]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_floats.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_floats.py index f64ec5570..b76743cf6 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_floats.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_floats.py @@ -9,11 +9,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tests/basic_lists/floats", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[List[float]]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_integers.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_integers.py index 859b09829..346bcf99f 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_integers.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_integers.py @@ -9,11 +9,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tests/basic_lists/integers", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[List[int]]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_strings.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_strings.py index 7d9261007..29606477e 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_strings.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_strings.py @@ -9,11 +9,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tests/basic_lists/strings", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[List[str]]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py index 0c1084cf6..ff055d3fd 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py @@ -54,12 +54,14 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tests/", "params": params, } + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py index dfedf685f..f4eef2510 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py @@ -21,12 +21,14 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/int_enum", "params": params, } + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py index e146b2ade..c43a0ca7e 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py @@ -12,16 +12,23 @@ def _get_kwargs( *, - json_body: AModel, + body: AModel, ) -> Dict[str, Any]: - json_json_body = json_body.to_dict() + headers: Dict[str, Any] = {} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/json_body", - "json": json_json_body, } + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -53,14 +60,14 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: AModel, + body: AModel, ) -> Response[Union[Any, HTTPValidationError]]: """Json Body Try sending a JSON body Args: - json_body (AModel): A Model for testing all the ways custom objects can be used + body (AModel): A Model for testing all the ways custom objects can be used Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -71,7 +78,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = client.get_httpx_client().request( @@ -84,14 +91,14 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], - json_body: AModel, + body: AModel, ) -> Optional[Union[Any, HTTPValidationError]]: """Json Body Try sending a JSON body Args: - json_body (AModel): A Model for testing all the ways custom objects can be used + body (AModel): A Model for testing all the ways custom objects can be used Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -103,21 +110,21 @@ def sync( return sync_detailed( client=client, - json_body=json_body, + body=body, ).parsed async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: AModel, + body: AModel, ) -> Response[Union[Any, HTTPValidationError]]: """Json Body Try sending a JSON body Args: - json_body (AModel): A Model for testing all the ways custom objects can be used + body (AModel): A Model for testing all the ways custom objects can be used Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -128,7 +135,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -139,14 +146,14 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], - json_body: AModel, + body: AModel, ) -> Optional[Union[Any, HTTPValidationError]]: """Json Body Try sending a JSON body Args: - json_body (AModel): A Model for testing all the ways custom objects can be used + body (AModel): A Model for testing all the ways custom objects can be used Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -159,6 +166,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, - json_body=json_body, + body=body, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/no_response_tests_no_response_get.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/no_response_tests_no_response_get.py index 5cd61aa15..670bb5663 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/no_response_tests_no_response_get.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/no_response_tests_no_response_get.py @@ -9,11 +9,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tests/no_response", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_get.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_get.py index 5cde2b110..231a7da74 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_get.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_get.py @@ -10,11 +10,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tests/octet_stream", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[File]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_post.py index e49e34d55..cb72ba657 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_post.py @@ -11,18 +11,23 @@ def _get_kwargs( *, - binary_body: File, + body: File, ) -> Dict[str, Any]: - headers = {} - headers["Content-Type"] = binary_body.mime_type if binary_body.mime_type else "application/octet-stream" + headers: Dict[str, Any] = {} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/octet_stream", - "content": binary_body.payload, - "headers": headers, } + _body = body.payload + + _kwargs["content"] = _body + headers["Content-Type"] = "application/octet-stream" + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -54,12 +59,12 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], - binary_body: File, + body: File, ) -> Response[Union[HTTPValidationError, str]]: """Binary (octet stream) request body Args: - binary_body (File): A file to upload + body (File): A file to upload Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -70,7 +75,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - binary_body=binary_body, + body=body, ) response = client.get_httpx_client().request( @@ -83,12 +88,12 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], - binary_body: File, + body: File, ) -> Optional[Union[HTTPValidationError, str]]: """Binary (octet stream) request body Args: - binary_body (File): A file to upload + body (File): A file to upload Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -100,19 +105,19 @@ def sync( return sync_detailed( client=client, - binary_body=binary_body, + body=body, ).parsed async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - binary_body: File, + body: File, ) -> Response[Union[HTTPValidationError, str]]: """Binary (octet stream) request body Args: - binary_body (File): A file to upload + body (File): A file to upload Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -123,7 +128,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - binary_body=binary_body, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -134,12 +139,12 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], - binary_body: File, + body: File, ) -> Optional[Union[HTTPValidationError, str]]: """Binary (octet stream) request body Args: - binary_body (File): A file to upload + body (File): A file to upload Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -152,6 +157,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, - binary_body=binary_body, + body=body, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data.py index d64cae452..93954ace9 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data.py @@ -10,14 +10,24 @@ def _get_kwargs( - form_data: AFormData, + *, + body: AFormData, ) -> Dict[str, Any]: - return { + headers: Dict[str, Any] = {} + + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/post_form_data", - "data": form_data.to_dict(), } + _body = body.to_dict() + + _kwargs["data"] = _body + headers["Content-Type"] = "application/x-www-form-urlencoded" + + _kwargs["headers"] = headers + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: @@ -40,12 +50,15 @@ def _build_response(*, client: Union[AuthenticatedClient, Client], response: htt def sync_detailed( *, client: Union[AuthenticatedClient, Client], - form_data: AFormData, + body: AFormData, ) -> Response[Any]: """Post form data Post form data + Args: + body (AFormData): + 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. @@ -55,7 +68,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - form_data=form_data, + body=body, ) response = client.get_httpx_client().request( @@ -68,12 +81,15 @@ def sync_detailed( async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - form_data: AFormData, + body: AFormData, ) -> Response[Any]: """Post form data Post form data + Args: + body (AFormData): + 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. @@ -83,7 +99,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - form_data=form_data, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data_inline.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data_inline.py index 2fde59a15..b676061a3 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data_inline.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data_inline.py @@ -5,19 +5,29 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.post_form_data_inline_data import PostFormDataInlineData +from ...models.post_form_data_inline_body import PostFormDataInlineBody from ...types import Response def _get_kwargs( - form_data: PostFormDataInlineData, + *, + body: PostFormDataInlineBody, ) -> Dict[str, Any]: - return { + headers: Dict[str, Any] = {} + + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/post_form_data_inline", - "data": form_data.to_dict(), } + _body = body.to_dict() + + _kwargs["data"] = _body + headers["Content-Type"] = "application/x-www-form-urlencoded" + + _kwargs["headers"] = headers + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: @@ -40,12 +50,15 @@ def _build_response(*, client: Union[AuthenticatedClient, Client], response: htt def sync_detailed( *, client: Union[AuthenticatedClient, Client], - form_data: PostFormDataInlineData, + body: PostFormDataInlineBody, ) -> Response[Any]: """Post form data (inline schema) Post form data (inline schema) + Args: + body (PostFormDataInlineBody): + 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. @@ -55,7 +68,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - form_data=form_data, + body=body, ) response = client.get_httpx_client().request( @@ -68,12 +81,15 @@ def sync_detailed( async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - form_data: PostFormDataInlineData, + body: PostFormDataInlineBody, ) -> Response[Any]: """Post form data (inline schema) Post form data (inline schema) + Args: + body (PostFormDataInlineBody): + 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. @@ -83,7 +99,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - form_data=form_data, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_tests_json_body_string.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_tests_json_body_string.py index c3614b375..909c77e78 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_tests_json_body_string.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_tests_json_body_string.py @@ -11,16 +11,23 @@ def _get_kwargs( *, - json_body: str, + body: str, ) -> Dict[str, Any]: - json_json_body = json_body + headers: Dict[str, Any] = {} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/json_body/string", - "json": json_json_body, } + _body = body + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -52,12 +59,12 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: str, + body: str, ) -> Response[Union[HTTPValidationError, str]]: """Json Body Which is String Args: - json_body (str): + body (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -68,7 +75,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = client.get_httpx_client().request( @@ -81,12 +88,12 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], - json_body: str, + body: str, ) -> Optional[Union[HTTPValidationError, str]]: """Json Body Which is String Args: - json_body (str): + body (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -98,19 +105,19 @@ def sync( return sync_detailed( client=client, - json_body=json_body, + body=body, ).parsed async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: str, + body: str, ) -> Response[Union[HTTPValidationError, str]]: """Json Body Which is String Args: - json_body (str): + body (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -121,7 +128,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -132,12 +139,12 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], - json_body: str, + body: str, ) -> Optional[Union[HTTPValidationError, str]]: """Json Body Which is String Args: - json_body (str): + body (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -150,6 +157,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, - json_body=json_body, + body=body, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py index 36f297c61..2a93ef5ad 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py @@ -5,23 +5,30 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.test_inline_objects_json_body import TestInlineObjectsJsonBody +from ...models.test_inline_objects_body import TestInlineObjectsBody from ...models.test_inline_objects_response_200 import TestInlineObjectsResponse200 from ...types import Response def _get_kwargs( *, - json_body: TestInlineObjectsJsonBody, + body: TestInlineObjectsBody, ) -> Dict[str, Any]: - json_json_body = json_body.to_dict() + headers: Dict[str, Any] = {} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/inline_objects", - "json": json_json_body, } + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -50,12 +57,12 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: TestInlineObjectsJsonBody, + body: TestInlineObjectsBody, ) -> Response[TestInlineObjectsResponse200]: """Test Inline Objects Args: - json_body (TestInlineObjectsJsonBody): + body (TestInlineObjectsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -66,7 +73,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = client.get_httpx_client().request( @@ -79,12 +86,12 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], - json_body: TestInlineObjectsJsonBody, + body: TestInlineObjectsBody, ) -> Optional[TestInlineObjectsResponse200]: """Test Inline Objects Args: - json_body (TestInlineObjectsJsonBody): + body (TestInlineObjectsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -96,19 +103,19 @@ def sync( return sync_detailed( client=client, - json_body=json_body, + body=body, ).parsed async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - json_body: TestInlineObjectsJsonBody, + body: TestInlineObjectsBody, ) -> Response[TestInlineObjectsResponse200]: """Test Inline Objects Args: - json_body (TestInlineObjectsJsonBody): + body (TestInlineObjectsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -119,7 +126,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - json_body=json_body, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -130,12 +137,12 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], - json_body: TestInlineObjectsJsonBody, + body: TestInlineObjectsBody, ) -> Optional[TestInlineObjectsResponse200]: """Test Inline Objects Args: - json_body (TestInlineObjectsJsonBody): + body (TestInlineObjectsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -148,6 +155,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, - json_body=json_body, + body=body, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/token_with_cookie_auth_token_with_cookie_get.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/token_with_cookie_auth_token_with_cookie_get.py index 5820cb934..0c68f4726 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/token_with_cookie_auth_token_with_cookie_get.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/token_with_cookie_auth_token_with_cookie_get.py @@ -15,12 +15,14 @@ def _get_kwargs( cookies = {} cookies["MyToken"] = my_token - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/auth/token_with_cookie", "cookies": cookies, } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/unsupported_content_tests_unsupported_content_get.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/unsupported_content_tests_unsupported_content_get.py index b3f5a95e6..a63b7b2a2 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/unsupported_content_tests_unsupported_content_get.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/unsupported_content_tests_unsupported_content_get.py @@ -9,11 +9,13 @@ def _get_kwargs() -> Dict[str, Any]: - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/tests/unsupported_content", } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py index 30a90393b..e36d4d92e 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py @@ -12,16 +12,22 @@ def _get_kwargs( *, - multipart_data: BodyUploadFileTestsUploadPost, + body: BodyUploadFileTestsUploadPost, ) -> Dict[str, Any]: - multipart_multipart_data = multipart_data.to_multipart() + headers: Dict[str, Any] = {} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/upload", - "files": multipart_multipart_data, } + _body = body.to_multipart() + + _kwargs["files"] = _body + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -53,14 +59,14 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], - multipart_data: BodyUploadFileTestsUploadPost, + body: BodyUploadFileTestsUploadPost, ) -> Response[Union[Any, HTTPValidationError]]: """Upload File Upload a file Args: - multipart_data (BodyUploadFileTestsUploadPost): + body (BodyUploadFileTestsUploadPost): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -71,7 +77,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - multipart_data=multipart_data, + body=body, ) response = client.get_httpx_client().request( @@ -84,14 +90,14 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], - multipart_data: BodyUploadFileTestsUploadPost, + body: BodyUploadFileTestsUploadPost, ) -> Optional[Union[Any, HTTPValidationError]]: """Upload File Upload a file Args: - multipart_data (BodyUploadFileTestsUploadPost): + body (BodyUploadFileTestsUploadPost): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -103,21 +109,21 @@ def sync( return sync_detailed( client=client, - multipart_data=multipart_data, + body=body, ).parsed async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - multipart_data: BodyUploadFileTestsUploadPost, + body: BodyUploadFileTestsUploadPost, ) -> Response[Union[Any, HTTPValidationError]]: """Upload File Upload a file Args: - multipart_data (BodyUploadFileTestsUploadPost): + body (BodyUploadFileTestsUploadPost): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -128,7 +134,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - multipart_data=multipart_data, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -139,14 +145,14 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], - multipart_data: BodyUploadFileTestsUploadPost, + body: BodyUploadFileTestsUploadPost, ) -> Optional[Union[Any, HTTPValidationError]]: """Upload File Upload a file Args: - multipart_data (BodyUploadFileTestsUploadPost): + body (BodyUploadFileTestsUploadPost): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -159,6 +165,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, - multipart_data=multipart_data, + body=body, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_multiple_files_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_multiple_files_tests_upload_post.py index a5cb511d1..6cfcfaa57 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_multiple_files_tests_upload_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_multiple_files_tests_upload_post.py @@ -11,20 +11,26 @@ def _get_kwargs( *, - multipart_data: List[File], + body: List[File], ) -> Dict[str, Any]: - multipart_multipart_data = [] - for multipart_data_item_data in multipart_data: - multipart_data_item = multipart_data_item_data.to_tuple() + headers: Dict[str, Any] = {} - multipart_multipart_data.append(multipart_data_item) - - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/tests/upload/multiple", - "files": multipart_multipart_data, } + _body = [] + for body_item_data in body: + body_item = body_item_data.to_tuple() + + _body.append(body_item) + + _kwargs["files"] = _body + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -56,14 +62,14 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], - multipart_data: List[File], + body: List[File], ) -> Response[Union[Any, HTTPValidationError]]: """Upload multiple files Upload several files in the same request Args: - multipart_data (List[File]): + body (List[File]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -74,7 +80,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - multipart_data=multipart_data, + body=body, ) response = client.get_httpx_client().request( @@ -87,14 +93,14 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], - multipart_data: List[File], + body: List[File], ) -> Optional[Union[Any, HTTPValidationError]]: """Upload multiple files Upload several files in the same request Args: - multipart_data (List[File]): + body (List[File]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -106,21 +112,21 @@ def sync( return sync_detailed( client=client, - multipart_data=multipart_data, + body=body, ).parsed async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - multipart_data: List[File], + body: List[File], ) -> Response[Union[Any, HTTPValidationError]]: """Upload multiple files Upload several files in the same request Args: - multipart_data (List[File]): + body (List[File]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -131,7 +137,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - multipart_data=multipart_data, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -142,14 +148,14 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], - multipart_data: List[File], + body: List[File], ) -> Optional[Union[Any, HTTPValidationError]]: """Upload multiple files Upload several files in the same request Args: - multipart_data (List[File]): + body (List[File]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -162,6 +168,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, - multipart_data=multipart_data, + body=body, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/true_/false_.py b/end_to_end_tests/golden-record/my_test_api_client/api/true_/false_.py index b747a3aa0..7921b332e 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/true_/false_.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/true_/false_.py @@ -18,12 +18,14 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - return { + _kwargs: Dict[str, Any] = { "method": "get", "url": "/naming/keywords", "params": params, } + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.OK: 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 d5be8c46c..5166f321b 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 @@ -37,6 +37,7 @@ from .get_location_header_types_string_enum_header import GetLocationHeaderTypesStringEnumHeader from .http_validation_error import HTTPValidationError from .import_ import Import +from .json_like_body import JsonLikeBody from .model_from_all_of import ModelFromAllOf from .model_name import ModelName from .model_reference_with_periods import ModelReferenceWithPeriods @@ -63,14 +64,17 @@ from .model_with_union_property_inlined_fruit_type_0 import ModelWithUnionPropertyInlinedFruitType0 from .model_with_union_property_inlined_fruit_type_1 import ModelWithUnionPropertyInlinedFruitType1 from .none import None_ -from .post_form_data_inline_data import PostFormDataInlineData -from .post_naming_property_conflict_with_import_json_body import PostNamingPropertyConflictWithImportJsonBody +from .post_bodies_multiple_data_body import PostBodiesMultipleDataBody +from .post_bodies_multiple_files_body import PostBodiesMultipleFilesBody +from .post_bodies_multiple_json_body import PostBodiesMultipleJsonBody +from .post_form_data_inline_body import PostFormDataInlineBody +from .post_naming_property_conflict_with_import_body import PostNamingPropertyConflictWithImportBody from .post_naming_property_conflict_with_import_response_200 import PostNamingPropertyConflictWithImportResponse200 from .post_responses_unions_simple_before_complex_response_200 import PostResponsesUnionsSimpleBeforeComplexResponse200 from .post_responses_unions_simple_before_complex_response_200a_type_1 import ( PostResponsesUnionsSimpleBeforeComplexResponse200AType1, ) -from .test_inline_objects_json_body import TestInlineObjectsJsonBody +from .test_inline_objects_body import TestInlineObjectsBody from .test_inline_objects_response_200 import TestInlineObjectsResponse200 from .validation_error import ValidationError @@ -106,6 +110,7 @@ "GetLocationHeaderTypesStringEnumHeader", "HTTPValidationError", "Import", + "JsonLikeBody", "ModelFromAllOf", "ModelName", "ModelReferenceWithPeriods", @@ -130,12 +135,15 @@ "ModelWithUnionPropertyInlinedFruitType0", "ModelWithUnionPropertyInlinedFruitType1", "None_", - "PostFormDataInlineData", - "PostNamingPropertyConflictWithImportJsonBody", + "PostBodiesMultipleDataBody", + "PostBodiesMultipleFilesBody", + "PostBodiesMultipleJsonBody", + "PostFormDataInlineBody", + "PostNamingPropertyConflictWithImportBody", "PostNamingPropertyConflictWithImportResponse200", "PostResponsesUnionsSimpleBeforeComplexResponse200", "PostResponsesUnionsSimpleBeforeComplexResponse200AType1", - "TestInlineObjectsJsonBody", + "TestInlineObjectsBody", "TestInlineObjectsResponse200", "ValidationError", ) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/json_like_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/json_like_body.py new file mode 100644 index 000000000..623dcd848 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/json_like_body.py @@ -0,0 +1,58 @@ +from typing import Any, Dict, List, Type, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="JsonLikeBody") + + +@_attrs_define +class JsonLikeBody: + """ + Attributes: + a (Union[Unset, str]): + """ + + a: Union[Unset, str] = UNSET + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a = self.a + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a is not UNSET: + field_dict["a"] = a + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + a = d.pop("a", UNSET) + + json_like_body = cls( + a=a, + ) + + json_like_body.additional_properties = d + return json_like_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 diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_data_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_data_body.py new file mode 100644 index 000000000..adc78cd6f --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_data_body.py @@ -0,0 +1,58 @@ +from typing import Any, Dict, List, Type, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostBodiesMultipleDataBody") + + +@_attrs_define +class PostBodiesMultipleDataBody: + """ + Attributes: + a (Union[Unset, str]): + """ + + a: Union[Unset, str] = UNSET + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a = self.a + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a is not UNSET: + field_dict["a"] = a + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + a = d.pop("a", UNSET) + + post_bodies_multiple_data_body = cls( + a=a, + ) + + post_bodies_multiple_data_body.additional_properties = d + return post_bodies_multiple_data_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 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 new file mode 100644 index 000000000..1c61d3385 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_files_body.py @@ -0,0 +1,71 @@ +from typing import Any, Dict, List, Type, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostBodiesMultipleFilesBody") + + +@_attrs_define +class PostBodiesMultipleFilesBody: + """ + Attributes: + a (Union[Unset, str]): + """ + + a: Union[Unset, str] = UNSET + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a = self.a + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a is not UNSET: + field_dict["a"] = a + + return field_dict + + def to_multipart(self) -> Dict[str, Any]: + a = self.a if isinstance(self.a, Unset) else (None, str(self.a).encode(), "text/plain") + + field_dict: Dict[str, Any] = {} + field_dict.update( + {key: (None, str(value).encode(), "text/plain") for key, value in self.additional_properties.items()} + ) + field_dict.update({}) + if a is not UNSET: + field_dict["a"] = a + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + a = d.pop("a", UNSET) + + post_bodies_multiple_files_body = cls( + a=a, + ) + + post_bodies_multiple_files_body.additional_properties = d + return post_bodies_multiple_files_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 diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_json_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_json_body.py new file mode 100644 index 000000000..88e5ec6f9 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/post_bodies_multiple_json_body.py @@ -0,0 +1,58 @@ +from typing import Any, Dict, List, Type, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostBodiesMultipleJsonBody") + + +@_attrs_define +class PostBodiesMultipleJsonBody: + """ + Attributes: + a (Union[Unset, str]): + """ + + a: Union[Unset, str] = UNSET + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a = self.a + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a is not UNSET: + field_dict["a"] = a + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + a = d.pop("a", UNSET) + + post_bodies_multiple_json_body = cls( + a=a, + ) + + post_bodies_multiple_json_body.additional_properties = d + return post_bodies_multiple_json_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 diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/post_form_data_inline_data.py b/end_to_end_tests/golden-record/my_test_api_client/models/post_form_data_inline_body.py similarity index 88% rename from end_to_end_tests/golden-record/my_test_api_client/models/post_form_data_inline_data.py rename to end_to_end_tests/golden-record/my_test_api_client/models/post_form_data_inline_body.py index 9e9007567..08a7bbc3a 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/post_form_data_inline_data.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/post_form_data_inline_body.py @@ -5,11 +5,11 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="PostFormDataInlineData") +T = TypeVar("T", bound="PostFormDataInlineBody") @_attrs_define -class PostFormDataInlineData: +class PostFormDataInlineBody: """ Attributes: a_required_field (str): @@ -44,13 +44,13 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: an_optional_field = d.pop("an_optional_field", UNSET) - post_form_data_inline_data = cls( + post_form_data_inline_body = cls( a_required_field=a_required_field, an_optional_field=an_optional_field, ) - post_form_data_inline_data.additional_properties = d - return post_form_data_inline_data + post_form_data_inline_body.additional_properties = d + return post_form_data_inline_body @property def additional_keys(self) -> List[str]: diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/post_naming_property_conflict_with_import_json_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/post_naming_property_conflict_with_import_body.py similarity index 83% rename from end_to_end_tests/golden-record/my_test_api_client/models/post_naming_property_conflict_with_import_json_body.py rename to end_to_end_tests/golden-record/my_test_api_client/models/post_naming_property_conflict_with_import_body.py index d6b280c6e..ed2f8efa1 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/post_naming_property_conflict_with_import_json_body.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/post_naming_property_conflict_with_import_body.py @@ -5,11 +5,11 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="PostNamingPropertyConflictWithImportJsonBody") +T = TypeVar("T", bound="PostNamingPropertyConflictWithImportBody") @_attrs_define -class PostNamingPropertyConflictWithImportJsonBody: +class PostNamingPropertyConflictWithImportBody: """ Attributes: field (Union[Unset, str]): A python_name of field should not interfere with attrs field @@ -42,13 +42,13 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: define = d.pop("Define", UNSET) - post_naming_property_conflict_with_import_json_body = cls( + post_naming_property_conflict_with_import_body = cls( field=field, define=define, ) - post_naming_property_conflict_with_import_json_body.additional_properties = d - return post_naming_property_conflict_with_import_json_body + post_naming_property_conflict_with_import_body.additional_properties = d + return post_naming_property_conflict_with_import_body @property def additional_keys(self) -> List[str]: diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_json_body.py b/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_body.py similarity index 80% rename from end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_json_body.py rename to end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_body.py index bf4c7d023..8c1843b41 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_json_body.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/test_inline_objects_body.py @@ -4,11 +4,11 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="TestInlineObjectsJsonBody") +T = TypeVar("T", bound="TestInlineObjectsBody") @_attrs_define -class TestInlineObjectsJsonBody: +class TestInlineObjectsBody: """ Attributes: a_property (Union[Unset, str]): @@ -31,8 +31,8 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() a_property = d.pop("a_property", UNSET) - test_inline_objects_json_body = cls( + test_inline_objects_body = cls( a_property=a_property, ) - return test_inline_objects_json_body + return test_inline_objects_body diff --git a/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/api/const/post_const_path.py b/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/api/const/post_const_path.py index 306968daf..2805064b2 100644 --- a/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/api/const/post_const_path.py +++ b/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/api/const/post_const_path.py @@ -5,17 +5,19 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.post_const_path_json_body import PostConstPathJsonBody +from ...models.post_const_path_body import PostConstPathBody from ...types import UNSET, Response, Unset def _get_kwargs( path: Literal["this goes in the path"], *, - json_body: PostConstPathJsonBody, + body: PostConstPathBody, required_query: Literal["this always goes in the query"], optional_query: Union[Literal["this sometimes goes in the query"], Unset] = UNSET, ) -> Dict[str, Any]: + headers: Dict[str, Any] = {} + params: Dict[str, Any] = {} params["required query"] = required_query @@ -24,17 +26,22 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - json_json_body = json_body.to_dict() - - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/const/{path}".format( path=path, ), - "json": json_json_body, "params": params, } + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -63,7 +70,7 @@ def sync_detailed( path: Literal["this goes in the path"], *, client: Union[AuthenticatedClient, Client], - json_body: PostConstPathJsonBody, + body: PostConstPathBody, required_query: Literal["this always goes in the query"], optional_query: Union[Literal["this sometimes goes in the query"], Unset] = UNSET, ) -> Response[Literal["Why have a fixed response? I dunno"]]: @@ -72,7 +79,7 @@ def sync_detailed( path (Literal['this goes in the path']): required_query (Literal['this always goes in the query']): optional_query (Union[Literal['this sometimes goes in the query'], Unset]): - json_body (PostConstPathJsonBody): + body (PostConstPathBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -84,7 +91,7 @@ def sync_detailed( kwargs = _get_kwargs( path=path, - json_body=json_body, + body=body, required_query=required_query, optional_query=optional_query, ) @@ -100,7 +107,7 @@ def sync( path: Literal["this goes in the path"], *, client: Union[AuthenticatedClient, Client], - json_body: PostConstPathJsonBody, + body: PostConstPathBody, required_query: Literal["this always goes in the query"], optional_query: Union[Literal["this sometimes goes in the query"], Unset] = UNSET, ) -> Optional[Literal["Why have a fixed response? I dunno"]]: @@ -109,7 +116,7 @@ def sync( path (Literal['this goes in the path']): required_query (Literal['this always goes in the query']): optional_query (Union[Literal['this sometimes goes in the query'], Unset]): - json_body (PostConstPathJsonBody): + body (PostConstPathBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -122,7 +129,7 @@ def sync( return sync_detailed( path=path, client=client, - json_body=json_body, + body=body, required_query=required_query, optional_query=optional_query, ).parsed @@ -132,7 +139,7 @@ async def asyncio_detailed( path: Literal["this goes in the path"], *, client: Union[AuthenticatedClient, Client], - json_body: PostConstPathJsonBody, + body: PostConstPathBody, required_query: Literal["this always goes in the query"], optional_query: Union[Literal["this sometimes goes in the query"], Unset] = UNSET, ) -> Response[Literal["Why have a fixed response? I dunno"]]: @@ -141,7 +148,7 @@ async def asyncio_detailed( path (Literal['this goes in the path']): required_query (Literal['this always goes in the query']): optional_query (Union[Literal['this sometimes goes in the query'], Unset]): - json_body (PostConstPathJsonBody): + body (PostConstPathBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -153,7 +160,7 @@ async def asyncio_detailed( kwargs = _get_kwargs( path=path, - json_body=json_body, + body=body, required_query=required_query, optional_query=optional_query, ) @@ -167,7 +174,7 @@ async def asyncio( path: Literal["this goes in the path"], *, client: Union[AuthenticatedClient, Client], - json_body: PostConstPathJsonBody, + body: PostConstPathBody, required_query: Literal["this always goes in the query"], optional_query: Union[Literal["this sometimes goes in the query"], Unset] = UNSET, ) -> Optional[Literal["Why have a fixed response? I dunno"]]: @@ -176,7 +183,7 @@ async def asyncio( path (Literal['this goes in the path']): required_query (Literal['this always goes in the query']): optional_query (Union[Literal['this sometimes goes in the query'], Unset]): - json_body (PostConstPathJsonBody): + body (PostConstPathBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -190,7 +197,7 @@ async def asyncio( await asyncio_detailed( path=path, client=client, - json_body=json_body, + body=body, required_query=required_query, optional_query=optional_query, ) diff --git a/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/__init__.py b/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/__init__.py index da482ad8b..df63ea1cd 100644 --- a/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/__init__.py +++ b/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/__init__.py @@ -1,5 +1,5 @@ """ Contains all the data models used in inputs/outputs """ -from .post_const_path_json_body import PostConstPathJsonBody +from .post_const_path_body import PostConstPathBody -__all__ = ("PostConstPathJsonBody",) +__all__ = ("PostConstPathBody",) diff --git a/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/post_const_path_json_body.py b/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/post_const_path_body.py similarity index 91% rename from end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/post_const_path_json_body.py rename to end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/post_const_path_body.py index e7cfcf3a8..387e693e0 100644 --- a/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/post_const_path_json_body.py +++ b/end_to_end_tests/test-3-1-golden-record/test_3_1_features_client/models/post_const_path_body.py @@ -5,11 +5,11 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="PostConstPathJsonBody") +T = TypeVar("T", bound="PostConstPathBody") @_attrs_define -class PostConstPathJsonBody: +class PostConstPathBody: """ Attributes: required (Literal['this always goes in the body']): @@ -57,14 +57,14 @@ def _parse_nullable(data: object) -> Union[Literal["this or null goes in the bod optional = d.pop("optional", UNSET) - post_const_path_json_body = cls( + post_const_path_body = cls( required=required, nullable=nullable, optional=optional, ) - post_const_path_json_body.additional_properties = d - return post_const_path_json_body + post_const_path_body.additional_properties = d + return post_const_path_body @property def additional_keys(self) -> List[str]: diff --git a/integration-tests/integration_tests/api/body/post_body_multipart.py b/integration-tests/integration_tests/api/body/post_body_multipart.py index 19d2b7d11..c64b4c4c2 100644 --- a/integration-tests/integration_tests/api/body/post_body_multipart.py +++ b/integration-tests/integration_tests/api/body/post_body_multipart.py @@ -5,7 +5,7 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.post_body_multipart_multipart_data import PostBodyMultipartMultipartData +from ...models.post_body_multipart_body import PostBodyMultipartBody from ...models.post_body_multipart_response_200 import PostBodyMultipartResponse200 from ...models.public_error import PublicError from ...types import Response @@ -13,16 +13,22 @@ def _get_kwargs( *, - multipart_data: PostBodyMultipartMultipartData, + body: PostBodyMultipartBody, ) -> Dict[str, Any]: - multipart_multipart_data = multipart_data.to_multipart() + headers: Dict[str, Any] = {} - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/body/multipart", - "files": multipart_multipart_data, } + _body = body.to_multipart() + + _kwargs["files"] = _body + + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response @@ -55,11 +61,11 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], - multipart_data: PostBodyMultipartMultipartData, + body: PostBodyMultipartBody, ) -> Response[Union[PostBodyMultipartResponse200, PublicError]]: """ Args: - multipart_data (PostBodyMultipartMultipartData): + body (PostBodyMultipartBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -70,7 +76,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - multipart_data=multipart_data, + body=body, ) response = client.get_httpx_client().request( @@ -83,11 +89,11 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], - multipart_data: PostBodyMultipartMultipartData, + body: PostBodyMultipartBody, ) -> Optional[Union[PostBodyMultipartResponse200, PublicError]]: """ Args: - multipart_data (PostBodyMultipartMultipartData): + body (PostBodyMultipartBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -99,18 +105,18 @@ def sync( return sync_detailed( client=client, - multipart_data=multipart_data, + body=body, ).parsed async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], - multipart_data: PostBodyMultipartMultipartData, + body: PostBodyMultipartBody, ) -> Response[Union[PostBodyMultipartResponse200, PublicError]]: """ Args: - multipart_data (PostBodyMultipartMultipartData): + body (PostBodyMultipartBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -121,7 +127,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - multipart_data=multipart_data, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -132,11 +138,11 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], - multipart_data: PostBodyMultipartMultipartData, + body: PostBodyMultipartBody, ) -> Optional[Union[PostBodyMultipartResponse200, PublicError]]: """ Args: - multipart_data (PostBodyMultipartMultipartData): + body (PostBodyMultipartBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -149,6 +155,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, - multipart_data=multipart_data, + body=body, ) ).parsed diff --git a/integration-tests/integration_tests/api/parameters/post_parameters_header.py b/integration-tests/integration_tests/api/parameters/post_parameters_header.py index a68dd841e..784eaf37f 100644 --- a/integration-tests/integration_tests/api/parameters/post_parameters_header.py +++ b/integration-tests/integration_tests/api/parameters/post_parameters_header.py @@ -17,7 +17,7 @@ def _get_kwargs( number_header: float, integer_header: int, ) -> Dict[str, Any]: - headers = {} + headers: Dict[str, Any] = {} headers["Boolean-Header"] = "true" if boolean_header else "false" headers["String-Header"] = string_header @@ -26,12 +26,14 @@ def _get_kwargs( headers["Integer-Header"] = str(integer_header) - return { + _kwargs: Dict[str, Any] = { "method": "post", "url": "/parameters/header", - "headers": headers, } + _kwargs["headers"] = headers + return _kwargs + def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response diff --git a/integration-tests/integration_tests/models/__init__.py b/integration-tests/integration_tests/models/__init__.py index 28d550bb2..0bc731d78 100644 --- a/integration-tests/integration_tests/models/__init__.py +++ b/integration-tests/integration_tests/models/__init__.py @@ -1,13 +1,13 @@ """ Contains all the data models used in inputs/outputs """ -from .post_body_multipart_multipart_data import PostBodyMultipartMultipartData +from .post_body_multipart_body import PostBodyMultipartBody from .post_body_multipart_response_200 import PostBodyMultipartResponse200 from .post_parameters_header_response_200 import PostParametersHeaderResponse200 from .problem import Problem from .public_error import PublicError __all__ = ( - "PostBodyMultipartMultipartData", + "PostBodyMultipartBody", "PostBodyMultipartResponse200", "PostParametersHeaderResponse200", "Problem", diff --git a/integration-tests/integration_tests/models/post_body_multipart_multipart_data.py b/integration-tests/integration_tests/models/post_body_multipart_body.py similarity index 91% rename from integration-tests/integration_tests/models/post_body_multipart_multipart_data.py rename to integration-tests/integration_tests/models/post_body_multipart_body.py index 526c489f4..de9992232 100644 --- a/integration-tests/integration_tests/models/post_body_multipart_multipart_data.py +++ b/integration-tests/integration_tests/models/post_body_multipart_body.py @@ -6,11 +6,11 @@ from ..types import UNSET, File, Unset -T = TypeVar("T", bound="PostBodyMultipartMultipartData") +T = TypeVar("T", bound="PostBodyMultipartBody") @_attrs_define -class PostBodyMultipartMultipartData: +class PostBodyMultipartBody: """ Attributes: a_string (str): @@ -81,14 +81,14 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: description = d.pop("description", UNSET) - post_body_multipart_multipart_data = cls( + post_body_multipart_body = cls( a_string=a_string, file=file, description=description, ) - post_body_multipart_multipart_data.additional_properties = d - return post_body_multipart_multipart_data + post_body_multipart_body.additional_properties = d + return post_body_multipart_body @property def additional_keys(self) -> List[str]: diff --git a/integration-tests/tests/test_api/test_body/test_post_body_multipart.py b/integration-tests/tests/test_api/test_body/test_post_body_multipart.py index d81dddab6..54498ebc5 100644 --- a/integration-tests/tests/test_api/test_body/test_post_body_multipart.py +++ b/integration-tests/tests/test_api/test_body/test_post_body_multipart.py @@ -5,7 +5,7 @@ from integration_tests.api.body import post_body_multipart from integration_tests.client import Client -from integration_tests.models.post_body_multipart_multipart_data import PostBodyMultipartMultipartData +from integration_tests.models.post_body_multipart_body import PostBodyMultipartBody from integration_tests.models.post_body_multipart_response_200 import PostBodyMultipartResponse200 from integration_tests.types import File @@ -19,7 +19,7 @@ def test(client: Client) -> None: response = post_body_multipart.sync_detailed( client=client, - multipart_data=PostBodyMultipartMultipartData( + body=PostBodyMultipartBody( a_string=a_string, file=File( payload=BytesIO(payload), @@ -65,7 +65,7 @@ def log_response(*_: Any, **__: Any) -> None: post_body_multipart.sync_detailed( client=client, - multipart_data=PostBodyMultipartMultipartData( + body=PostBodyMultipartBody( a_string=a_string, file=File( payload=BytesIO(payload), @@ -90,7 +90,7 @@ def test_context_manager(client: Client) -> None: with client as client: post_body_multipart.sync_detailed( client=client, - multipart_data=PostBodyMultipartMultipartData( + body=PostBodyMultipartBody( a_string=a_string, file=File( payload=BytesIO(payload), @@ -102,7 +102,7 @@ def test_context_manager(client: Client) -> None: ) response = post_body_multipart.sync_detailed( client=client, - multipart_data=PostBodyMultipartMultipartData( + body=PostBodyMultipartBody( a_string=a_string, file=File( payload=BytesIO(payload), @@ -116,7 +116,7 @@ def test_context_manager(client: Client) -> None: with pytest.raises(RuntimeError): post_body_multipart.sync_detailed( client=client, - multipart_data=PostBodyMultipartMultipartData( + body=PostBodyMultipartBody( a_string=a_string, file=File( payload=BytesIO(payload), @@ -148,7 +148,7 @@ async def test_async(client: Client) -> None: response = await post_body_multipart.asyncio_detailed( client=client, - multipart_data=PostBodyMultipartMultipartData( + body=PostBodyMultipartBody( a_string=a_string, file=File( payload=BytesIO(payload), @@ -181,7 +181,7 @@ async def test_async_context_manager(client: Client) -> None: async with client as client: await post_body_multipart.asyncio_detailed( client=client, - multipart_data=PostBodyMultipartMultipartData( + body=PostBodyMultipartBody( a_string=a_string, file=File( payload=BytesIO(payload), @@ -193,7 +193,7 @@ async def test_async_context_manager(client: Client) -> None: ) response = await post_body_multipart.asyncio_detailed( client=client, - multipart_data=PostBodyMultipartMultipartData( + body=PostBodyMultipartBody( a_string=a_string, file=File( payload=BytesIO(payload), @@ -207,7 +207,7 @@ async def test_async_context_manager(client: Client) -> None: with pytest.raises(RuntimeError): await post_body_multipart.asyncio_detailed( client=client, - multipart_data=PostBodyMultipartMultipartData( + body=PostBodyMultipartBody( a_string=a_string, file=File( payload=BytesIO(payload), diff --git a/openapi_python_client/parser/bodies.py b/openapi_python_client/parser/bodies.py new file mode 100644 index 000000000..9ab42cb4f --- /dev/null +++ b/openapi_python_client/parser/bodies.py @@ -0,0 +1,125 @@ +import sys +from typing import List, Tuple, Union + +import attr + +from openapi_python_client.parser.properties import ( + ModelProperty, + Property, + Schemas, + property_from_data, +) + +from .. import schema as oai +from ..config import Config +from ..utils import get_content_type +from .errors import ErrorLevel, ParseError + +if sys.version_info >= (3, 11): + from enum import StrEnum + + class BodyType(StrEnum): + JSON = "json" + DATA = "data" + FILES = "files" + CONTENT = "content" +else: + from enum import Enum + + class BodyType(str, Enum): + JSON = "json" + DATA = "data" + FILES = "files" + CONTENT = "content" + + +@attr.define +class Body: + content_type: str + prop: Property + body_type: BodyType + + +def body_from_data( + *, + data: oai.Operation, + schemas: Schemas, + config: Config, + endpoint_name: str, +) -> Tuple[List[Union[Body, ParseError]], Schemas]: + """Adds form or JSON body to Endpoint if included in data""" + if data.request_body is None or isinstance(data.request_body, oai.Reference): + return [], schemas + + bodies: List[Union[Body, ParseError]] = [] + body_content = data.request_body.content + prefix_type_names = len(body_content) > 1 + + for content_type, media_type in body_content.items(): + simplified_content_type = get_content_type(content_type) + if simplified_content_type is None: + bodies.append( + ParseError( + detail="Invalid content type", + data=data.request_body, + level=ErrorLevel.WARNING, + ) + ) + continue + media_type_schema = media_type.media_type_schema + if media_type_schema is None: + bodies.append( + ParseError( + detail="Missing schema", + data=data.request_body, + level=ErrorLevel.WARNING, + ) + ) + continue + if simplified_content_type == "application/x-www-form-urlencoded": + body_type = BodyType.DATA + elif simplified_content_type == "multipart/form-data": + body_type = BodyType.FILES + elif simplified_content_type == "application/octet-stream": + body_type = BodyType.CONTENT + elif simplified_content_type == "application/json" or simplified_content_type.endswith("+json"): + body_type = BodyType.JSON + else: + bodies.append( + ParseError( + detail=f"Unsupported content type {simplified_content_type}", + data=data.request_body, + level=ErrorLevel.WARNING, + ) + ) + continue + prop, schemas = property_from_data( + name="body", + required=True, + data=media_type_schema, + schemas=schemas, + parent_name=f"{endpoint_name}_{body_type}" if prefix_type_names else endpoint_name, + config=config, + ) + if isinstance(prop, ParseError): + bodies.append(prop) + continue + if isinstance(prop, ModelProperty) and body_type == BodyType.FILES: + # Regardless of if we just made this property or found it, it now needs the `to_multipart` method + prop = attr.evolve(prop, is_multipart_body=True) + schemas = attr.evolve( + schemas, + classes_by_name={ + **schemas.classes_by_name, + prop.class_info.name: prop, + }, + ) + bodies.append( + Body( + content_type=content_type, + prop=prop, + body_type=body_type, + ) + ) + + return bodies, schemas diff --git a/openapi_python_client/parser/openapi.py b/openapi_python_client/parser/openapi.py index 299542b2b..37d50bca5 100644 --- a/openapi_python_client/parser/openapi.py +++ b/openapi_python_client/parser/openapi.py @@ -5,13 +5,13 @@ from http import HTTPStatus from typing import Any, Dict, Iterator, List, Optional, Protocol, Set, Tuple, Union -import attr from pydantic import ValidationError from .. import schema as oai from .. import utils from ..config import Config -from ..utils import PythonIdentifier, get_content_type +from ..utils import PythonIdentifier +from .bodies import Body, body_from_data from .errors import GeneratorError, ParseError, PropertyError from .properties import ( AnyProperty, @@ -139,161 +139,10 @@ class Endpoint: header_parameters: Dict[str, Property] = field(default_factory=dict) cookie_parameters: Dict[str, Property] = field(default_factory=dict) responses: List[Response] = field(default_factory=list) - form_body: Optional[Property] = None - json_body: Optional[Property] = None - multipart_body: Optional[Property] = None - binary_body: Optional[Property] = None + bodies: List[Body] = field(default_factory=list) errors: List[ParseError] = field(default_factory=list) used_python_identifiers: Set[PythonIdentifier] = field(default_factory=set) - @staticmethod - def parse_request_form_body( - *, body: oai.RequestBody, schemas: Schemas, parent_name: str, config: Config - ) -> Tuple[Union[Property, PropertyError, None], Schemas]: - """Return form_body and updated schemas""" - body_content = body.content - form_body = body_content.get("application/x-www-form-urlencoded") - if form_body is not None and form_body.media_type_schema is not None: - prop, schemas = property_from_data( - name="data", - required=True, - data=form_body.media_type_schema, - schemas=schemas, - parent_name=parent_name, - config=config, - ) - if isinstance(prop, ModelProperty): - schemas = attr.evolve( - schemas, - classes_by_name={ - **schemas.classes_by_name, - prop.class_info.name: prop, - }, - ) - return prop, schemas - return None, schemas - - @staticmethod - def parse_multipart_body( - *, body: oai.RequestBody, schemas: Schemas, parent_name: str, config: Config - ) -> Tuple[Union[Property, PropertyError, None], Schemas]: - """Return multipart_body""" - body_content = body.content - multipart_body = body_content.get("multipart/form-data") - if multipart_body is not None and multipart_body.media_type_schema is not None: - prop, schemas = property_from_data( - name="multipart_data", - required=True, - data=multipart_body.media_type_schema, - schemas=schemas, - parent_name=parent_name, - config=config, - ) - if isinstance(prop, ModelProperty): - prop = attr.evolve(prop, is_multipart_body=True) - schemas = attr.evolve( - schemas, - classes_by_name={ - **schemas.classes_by_name, - prop.class_info.name: prop, - }, - ) - return prop, schemas - return None, schemas - - @staticmethod - def parse_request_json_body( - *, body: oai.RequestBody, schemas: Schemas, parent_name: str, config: Config - ) -> Tuple[Union[Property, PropertyError, None], Schemas]: - """Return json_body""" - json_body = None - for content_type, schema in body.content.items(): - parsed_content_type = get_content_type(content_type) - - if parsed_content_type is not None and ( - parsed_content_type == "application/json" or parsed_content_type.endswith("+json") - ): - json_body = schema - break - - if json_body is not None and json_body.media_type_schema is not None: - return property_from_data( - name="json_body", - required=True, - data=json_body.media_type_schema, - schemas=schemas, - parent_name=parent_name, - config=config, - ) - return None, schemas - - @staticmethod - def parse_request_binary_body( - *, body: oai.RequestBody, schemas: Schemas, parent_name: str, config: Config - ) -> Tuple[Union[Property, PropertyError, None], Schemas]: - """Return binary_body""" - binary_body = None - for content_type, schema in body.content.items(): - parsed_content_type = get_content_type(content_type) - - if parsed_content_type == "application/octet-stream": - binary_body = schema - break - - if binary_body is not None and binary_body.media_type_schema is not None: - return property_from_data( - name="binary_body", - required=True, - data=binary_body.media_type_schema, - schemas=schemas, - parent_name=parent_name, - config=config, - ) - return None, schemas - - @staticmethod - def _add_body( - *, - endpoint: "Endpoint", - data: oai.Operation, - schemas: Schemas, - config: Config, - ) -> Tuple[Union[ParseError, "Endpoint"], Schemas]: - """Adds form or JSON body to Endpoint if included in data""" - endpoint = deepcopy(endpoint) - if data.requestBody is None or isinstance(data.requestBody, oai.Reference): - return endpoint, schemas - - request_body_parsers: List[Tuple[str, RequestBodyParser]] = [ - ("form_body", Endpoint.parse_request_form_body), - ("json_body", Endpoint.parse_request_json_body), - ("binary_body", Endpoint.parse_request_binary_body), - ("multipart_body", Endpoint.parse_multipart_body), - ] - - for property_name, parser in request_body_parsers: - body, schemas = parser(body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config) - - if isinstance(body, ParseError): - property_type = property_name - if property_type.endswith("_body"): - property_type = property_type[:-5] - return ( - ParseError( - header=f"Cannot parse {property_type} request body of endpoint {endpoint.name}", - detail=body.detail, - data=body.data, - ), - schemas, - ) - - if body is not None: - setattr(endpoint, property_name, body) - endpoint.relative_imports.update(body.get_imports(prefix=models_relative_prefix)) - endpoint.relative_imports.update(body.get_lazy_imports(prefix=models_relative_prefix)) - - return endpoint, schemas - @staticmethod def _add_responses( *, endpoint: "Endpoint", data: oai.Responses, schemas: Schemas, config: Config @@ -559,7 +408,28 @@ def from_data( if isinstance(result, ParseError): return result, schemas, parameters result, schemas = Endpoint._add_responses(endpoint=result, data=data.responses, schemas=schemas, config=config) - result, schemas = Endpoint._add_body(endpoint=result, data=data, schemas=schemas, config=config) + if isinstance(result, ParseError): + return result, schemas, parameters + bodies, schemas = body_from_data(data=data, schemas=schemas, config=config, endpoint_name=result.name) + body_errors = [] + for body in bodies: + if isinstance(body, ParseError): + body_errors.append(body) + continue + result.bodies.append(body) + result.relative_imports.update(body.prop.get_imports(prefix=models_relative_prefix)) + result.relative_imports.update(body.prop.get_lazy_imports(prefix=models_relative_prefix)) + if len(result.bodies) > 0: + result.errors.extend(body_errors) + elif len(body_errors) > 0: + return ( + ParseError( + header="Endpoint requires a body, but none were parseable.", + detail="\n".join(error.detail or "" for error in body_errors), + ), + schemas, + parameters, + ) return result, schemas, parameters @@ -578,12 +448,7 @@ def iter_all_parameters(self) -> Iterator[Property]: yield from self.query_parameters.values() yield from self.header_parameters.values() yield from self.cookie_parameters.values() - if self.multipart_body: - yield self.multipart_body - if self.json_body: - yield self.json_body - if self.binary_body: - yield self.binary_body + yield from (body.prop for body in self.bodies) def list_all_parameters(self) -> List[Property]: """Return a List of all the parameters of this endpoint""" diff --git a/openapi_python_client/schema/openapi_schema_pydantic/operation.py b/openapi_python_client/schema/openapi_schema_pydantic/operation.py index 7dd7f8f15..41f5e7100 100644 --- a/openapi_python_client/schema/openapi_schema_pydantic/operation.py +++ b/openapi_python_client/schema/openapi_schema_pydantic/operation.py @@ -1,6 +1,6 @@ from typing import Dict, List, Optional, Union -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from .callback import Callback from .external_documentation import ExternalDocumentation @@ -30,7 +30,7 @@ class Operation(BaseModel): externalDocs: Optional[ExternalDocumentation] = None operationId: Optional[str] = None parameters: Optional[List[Union[Parameter, Reference]]] = None - requestBody: Optional[Union[RequestBody, Reference]] = None + request_body: Optional[Union[RequestBody, Reference]] = Field(None, alias="requestBody") responses: Responses callbacks: Optional[Dict[str, Callback]] = None @@ -60,8 +60,14 @@ class Operation(BaseModel): "schema": { "type": "object", "properties": { - "name": {"description": "Updated name of the pet", "type": "string"}, - "status": {"description": "Updated status of the pet", "type": "string"}, + "name": { + "description": "Updated name of the pet", + "type": "string", + }, + "status": { + "description": "Updated status of the pet", + "type": "string", + }, }, "required": ["status"], } diff --git a/openapi_python_client/templates/endpoint_macros.py.jinja b/openapi_python_client/templates/endpoint_macros.py.jinja index f5904a509..b4a7713fe 100644 --- a/openapi_python_client/templates/endpoint_macros.py.jinja +++ b/openapi_python_client/templates/endpoint_macros.py.jinja @@ -2,8 +2,8 @@ {% from "helpers.jinja" import safe_docstring %} {% macro header_params(endpoint) %} -{% if endpoint.header_parameters or endpoint.binary_body %} -headers = {} +{% if endpoint.header_parameters or endpoint.bodies | length > 0 %} +headers: Dict[str, Any] = {} {% if endpoint.header_parameters %} {% for parameter in endpoint.header_parameters.values() %} {% import "property_templates/" + parameter.template as param_template %} @@ -16,9 +16,6 @@ headers = {} {{ guarded_statement(parameter, parameter.python_name, statement) }} {% endfor %} {% endif %} -{% if endpoint.binary_body %} -headers['Content-Type'] = {{ endpoint.binary_body.python_name }}.mime_type if {{ endpoint.binary_body.python_name}}.mime_type else 'application/octet-stream' -{% endif %} {% endif %} {% endmacro %} @@ -61,27 +58,33 @@ params = {k: v for k, v in params.items() if v is not UNSET and v is not None} {% endif %} {% endmacro %} -{% macro json_body(endpoint) %} -{% if endpoint.json_body %} - {% set property = endpoint.json_body %} - {% set destination = "json_" + property.python_name %} - {% import "property_templates/" + property.template as prop_template %} - {% if prop_template.transform %} +{% macro body_to_kwarg(body, destination) %} +{% if body.body_type == "data" %} +{{ destination }} = body.to_dict() +{% elif body.body_type == "files"%} +{{ multipart_body(body, destination) }} +{% elif body.body_type == "json" %} +{{ json_body(body, destination) }} +{% elif body.body_type == "content" %} +{{ destination }} = body.payload +{% endif %} +{% endmacro %} + +{% macro json_body(body, destination) %} +{% set property = body.prop %} +{% import "property_templates/" + property.template as prop_template %} +{% if prop_template.transform %} {{ prop_template.transform(property, property.python_name, destination) }} - {% else %} +{% else %} {{ destination }} = {{ property.python_name }} - {% endif %} {% endif %} {% endmacro %} -{% macro multipart_body(endpoint) %} -{% if endpoint.multipart_body %} - {% set property = endpoint.multipart_body %} - {% set destination = "multipart_" + property.python_name %} - {% import "property_templates/" + property.template as prop_template %} - {% if prop_template.transform_multipart %} +{% macro multipart_body(body, destination) %} +{% set property = body.prop %} +{% import "property_templates/" + property.template as prop_template %} +{% if prop_template.transform_multipart %} {{ prop_template.transform_multipart(property, property.python_name, destination) }} - {% endif %} {% endif %} {% endmacro %} @@ -102,20 +105,15 @@ client: AuthenticatedClient, client: Union[AuthenticatedClient, Client], {% endif %} {% endif %} -{# Form data if any #} -{% if endpoint.form_body %} -form_data: {{ endpoint.form_body.get_type_string() }}, -{% endif %} -{# Multipart data if any #} -{% if endpoint.multipart_body %} -multipart_data: {{ endpoint.multipart_body.get_type_string() }}, -{% endif %} -{# JSON body if any #} -{% if endpoint.json_body %} -json_body: {{ endpoint.json_body.get_type_string() }}, -{% endif %} -{% if endpoint.binary_body %} -binary_body: {{ endpoint.binary_body.get_type_string() }}, +{# Any allowed bodies #} +{% if endpoint.bodies | length == 1 %} +body: {{ endpoint.bodies[0].prop.get_type_string() }}, +{% elif endpoint.bodies | length > 1 %} +body: Union[ + {% for body in endpoint.bodies %} + {{ body.prop.get_type_string() }}, + {% endfor %} +], {% endif %} {# query parameters #} {% for parameter in endpoint.query_parameters.values() %} @@ -138,17 +136,8 @@ binary_body: {{ endpoint.binary_body.get_type_string() }}, {% if include_client %} client=client, {% endif %} -{% if endpoint.form_body %} -form_data=form_data, -{% endif %} -{% if endpoint.multipart_body %} -multipart_data=multipart_data, -{% endif %} -{% if endpoint.json_body %} -json_body=json_body, -{% endif %} -{% if endpoint.binary_body %} -binary_body=binary_body, +{% if endpoint.bodies | length > 0 %} +body=body, {% endif %} {% for parameter in endpoint.query_parameters.values() %} {{ parameter.python_name }}={{ parameter.python_name }}, diff --git a/openapi_python_client/templates/endpoint_module.py.jinja b/openapi_python_client/templates/endpoint_module.py.jinja index 3aec2dcfc..8bd4430d7 100644 --- a/openapi_python_client/templates/endpoint_module.py.jinja +++ b/openapi_python_client/templates/endpoint_module.py.jinja @@ -11,8 +11,8 @@ from ... import errors {{ relative }} {% endfor %} -{% from "endpoint_macros.py.jinja" import header_params, cookie_params, query_params, json_body, multipart_body, - arguments, client, kwargs, parse_response, docstring %} +{% from "endpoint_macros.py.jinja" import header_params, cookie_params, query_params, + arguments, client, kwargs, parse_response, docstring, body_to_kwarg %} {% set return_string = endpoint.response_type() %} {% set parsed_responses = (endpoint.responses | length > 0) and return_string != "Any" %} @@ -26,41 +26,47 @@ def _get_kwargs( {{ query_params(endpoint) | indent(4) }} - {{ json_body(endpoint) | indent(4) }} - - {{ multipart_body(endpoint) | indent(4) }} - - return { + _kwargs: Dict[str, Any] = { "method": "{{ endpoint.method }}", - {% if endpoint.path_parameters %} + {% if endpoint.path_parameters %} "url": "{{ endpoint.path }}".format( {%- for parameter in endpoint.path_parameters.values() -%} - {{parameter.name}}={{parameter.python_name}}, + {{parameter.name}}={{parameter.python_name}}, {%- endfor -%} ), - {% else %} + {% else %} "url": "{{ endpoint.path }}", - {% endif %} - {% if endpoint.form_body %} - "data": form_data.to_dict(), - {% elif endpoint.multipart_body %} - "files": {{ "multipart_" + endpoint.multipart_body.python_name }}, - {% elif endpoint.json_body %} - "json": {{ "json_" + endpoint.json_body.python_name }}, - {% elif endpoint.binary_body %} - "content": {{ endpoint.binary_body.python_name }}.payload, - {% endif %} - {% if endpoint.query_parameters %} + {% endif %} + {% if endpoint.query_parameters %} "params": params, - {% endif %} - {% if endpoint.header_parameters or endpoint.binary_body %} - "headers": headers, - {% endif %} - {% if endpoint.cookie_parameters %} + {% endif %} + {% if endpoint.cookie_parameters %} "cookies": cookies, - {% endif %} + {% endif %} } +{% if endpoint.bodies | length > 1 %} +{% for body in endpoint.bodies %} + if isinstance(body, {{body.prop.get_type_string() }}): + {% set destination = "_" + body.body_type + "_body" %} + {{ body_to_kwarg(body, destination) | indent(8) }} + _kwargs["{{ body.body_type.value }}"] = {{ destination }} + headers["Content-Type"] = "{{ body.content_type }}" +{% endfor %} +{% elif endpoint.bodies | length == 1 %} +{% set body = endpoint.bodies[0] %} + {{ body_to_kwarg(body, "_body") | indent(4) }} + _kwargs["{{ body.body_type.value }}"] = _body + {% if body.content_type != "multipart/form-data" %}{# Need httpx to set the boundary automatically #} + headers["Content-Type"] = "{{ body.content_type }}" + {% endif %} +{% endif %} + +{% if endpoint.header_parameters or endpoint.bodies | length > 0 %} + _kwargs["headers"] = headers +{% endif %} + return _kwargs + def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[{{ return_string }}]: {% for response in endpoint.responses %} diff --git a/tests/test_parser/test_bodies.py b/tests/test_parser/test_bodies.py new file mode 100644 index 000000000..6641905f8 --- /dev/null +++ b/tests/test_parser/test_bodies.py @@ -0,0 +1,39 @@ +from openapi_python_client import Config +from openapi_python_client import schema as oai +from openapi_python_client.parser.bodies import body_from_data +from openapi_python_client.parser.errors import ParseError +from openapi_python_client.parser.properties import Schemas + + +def test_errors(): + operation = oai.Operation( + requestBody=oai.RequestBody( + content={ + "invalid content type": oai.MediaType( + media_type_schema=oai.Schema( + type=oai.DataType.STRING, + ) + ), + "application/json": oai.MediaType( + media_type_schema=None # Missing media type schema is an error + ), + "text/html": oai.MediaType( # content type not supported by the generator + media_type_schema=oai.Schema( + type=oai.DataType.STRING, + ) + ), + "application/sushi+json": oai.MediaType( + media_type_schema=oai.Schema( + type=oai.DataType.INTEGER, + default="make this an invalid property", + ) + ), + } + ), + responses={}, + ) + + errs, _ = body_from_data(data=operation, schemas=Schemas(), config=Config(), endpoint_name="this will not succeed") + + assert len(errs) == len(operation.request_body.content) + assert all(isinstance(err, ParseError) for err in errs) diff --git a/tests/test_parser/test_openapi.py b/tests/test_parser/test_openapi.py index b304271d7..a92cc7845 100644 --- a/tests/test_parser/test_openapi.py +++ b/tests/test_parser/test_openapi.py @@ -8,6 +8,7 @@ from openapi_python_client.parser.errors import ParseError from openapi_python_client.parser.openapi import Endpoint, EndpointCollection from openapi_python_client.parser.properties import IntProperty, Parameters, Schemas +from openapi_python_client.schema import DataType MODULE_NAME = "openapi_python_client.parser.openapi" @@ -126,357 +127,6 @@ def make_endpoint(self): relative_imports={"import_3"}, ) - def test_parse_request_form_body(self, mocker, model_property_factory): - from openapi_python_client.parser.properties import Class - - schema = oai.Reference.model_construct(ref=mocker.MagicMock()) - body = oai.RequestBody.model_construct( - content={"application/x-www-form-urlencoded": oai.MediaType.model_construct(media_type_schema=schema)} - ) - class_info = Class(name="class_name", module_name="module_name") - prop_before = model_property_factory(class_info=class_info) - schemas_before = Schemas() - property_from_data = mocker.patch( - f"{MODULE_NAME}.property_from_data", return_value=(prop_before, schemas_before) - ) - config = mocker.MagicMock() - - from openapi_python_client.parser.openapi import Endpoint - - result = Endpoint.parse_request_form_body(body=body, schemas=schemas_before, parent_name="name", config=config) - - property_from_data.assert_called_once_with( - name="data", required=True, data=schema, schemas=schemas_before, parent_name="name", config=config - ) - prop_after = model_property_factory(class_info=class_info) - schemas_after = Schemas(classes_by_name={class_info.name: prop_after}) - assert result == (prop_after, schemas_after) - - def test_parse_request_form_body_no_data(self): - body = oai.RequestBody.model_construct(content={}) - config = MagicMock() - schemas = MagicMock() - - from openapi_python_client.parser.openapi import Endpoint - - result = Endpoint.parse_request_form_body(body=body, schemas=schemas, parent_name="name", config=config) - - assert result == (None, schemas) - - def test_parse_multipart_body(self, mocker, model_property_factory): - from openapi_python_client.parser.openapi import Endpoint, Schemas - from openapi_python_client.parser.properties import Class - - class_info = Class(name="class_name", module_name="module_name") - prop_before = model_property_factory(class_info=class_info, is_multipart_body=False) - - schema = mocker.MagicMock() - body = oai.RequestBody.model_construct( - content={"multipart/form-data": oai.MediaType.model_construct(media_type_schema=schema)} - ) - schemas_before = Schemas() - config = MagicMock() - property_from_data = mocker.patch( - f"{MODULE_NAME}.property_from_data", return_value=(prop_before, schemas_before) - ) - - result = Endpoint.parse_multipart_body(body=body, schemas=schemas_before, parent_name="parent", config=config) - - property_from_data.assert_called_once_with( - name="multipart_data", - required=True, - data=schema, - schemas=schemas_before, - parent_name="parent", - config=config, - ) - prop_after = model_property_factory(class_info=class_info, is_multipart_body=True) - schemas_after = Schemas(classes_by_name={class_info.name: prop_after}) - assert result == (prop_after, schemas_after) - - def test_parse_multipart_body_existing_schema(self, mocker, model_property_factory): - from openapi_python_client.parser.openapi import Endpoint, Schemas - from openapi_python_client.parser.properties import Class - - class_info = Class(name="class_name", module_name="module_name") - prop_before = model_property_factory(class_info=class_info, is_multipart_body=False) - schemas_before = Schemas(classes_by_name={class_info.name: prop_before}) - - schema = mocker.MagicMock() - body = oai.RequestBody.model_construct( - content={"multipart/form-data": oai.MediaType.model_construct(media_type_schema=schema)} - ) - config = MagicMock() - property_from_data = mocker.patch( - f"{MODULE_NAME}.property_from_data", return_value=(prop_before, schemas_before) - ) - - result = Endpoint.parse_multipart_body(body=body, schemas=schemas_before, parent_name="parent", config=config) - - property_from_data.assert_called_once_with( - name="multipart_data", - required=True, - data=schema, - schemas=schemas_before, - parent_name="parent", - config=config, - ) - prop_after = model_property_factory(class_info=class_info, is_multipart_body=True) - schemas_after = Schemas(classes_by_name={class_info.name: prop_after}) - assert result == (prop_after, schemas_after) - - def test_parse_multipart_body_no_data(self): - from openapi_python_client.parser.openapi import Endpoint, Schemas - - body = oai.RequestBody.model_construct(content={}) - schemas = Schemas() - - prop, schemas = Endpoint.parse_multipart_body( - body=body, schemas=schemas, parent_name="parent", config=MagicMock() - ) - - assert prop is None - - @pytest.mark.parametrize( - "content_type", - ( - "application/json", - "application/vnd.api+json", - "application/yang-data+json", - "application/json;charset=utf-8", - ), - ) - def test_parse_request_json_body(self, mocker, content_type): - from openapi_python_client.parser.openapi import Endpoint, Schemas - - schema = mocker.MagicMock() - body = oai.RequestBody.model_construct( - content={content_type: oai.MediaType.model_construct(media_type_schema=schema)} - ) - property_from_data = mocker.patch(f"{MODULE_NAME}.property_from_data") - schemas = Schemas() - config = MagicMock() - - result = Endpoint.parse_request_json_body(body=body, schemas=schemas, parent_name="parent", config=config) - - property_from_data.assert_called_once_with( - name="json_body", required=True, data=schema, schemas=schemas, parent_name="parent", config=config - ) - assert result == property_from_data.return_value - - def test_parse_request_json_body_no_data(self): - from openapi_python_client.parser.openapi import Endpoint, Schemas - - body = oai.RequestBody.model_construct(content={}) - schemas = Schemas() - - result = Endpoint.parse_request_json_body(body=body, schemas=schemas, parent_name="parent", config=MagicMock()) - - assert result == (None, schemas) - - def test_add_body_no_data(self, mocker): - from openapi_python_client.parser.openapi import Endpoint, Schemas - - parse_request_form_body = mocker.patch.object(Endpoint, "parse_request_form_body") - endpoint = self.make_endpoint() - schemas = Schemas() - - Endpoint._add_body(endpoint=endpoint, data=oai.Operation.model_construct(), schemas=schemas, config=MagicMock()) - - parse_request_form_body.assert_not_called() - - def test_add_body_bad_json_data(self, mocker): - from openapi_python_client.parser.openapi import Endpoint, Schemas - - schemas = Schemas() - mocker.patch.object(Endpoint, "parse_request_form_body", return_value=(None, schemas)) - parse_error = ParseError(data=mocker.MagicMock(), detail=mocker.MagicMock()) - other_schemas = mocker.MagicMock() - mocker.patch.object(Endpoint, "parse_request_json_body", return_value=(parse_error, other_schemas)) - endpoint = self.make_endpoint() - request_body = mocker.MagicMock() - - result = Endpoint._add_body( - endpoint=endpoint, - data=oai.Operation.model_construct(requestBody=request_body), - schemas=schemas, - config=MagicMock(), - ) - - assert result == ( - ParseError( - header=f"Cannot parse json request body of endpoint {endpoint.name}", - detail=parse_error.detail, - data=parse_error.data, - ), - other_schemas, - ) - - def test_add_body_bad_binary_data(self, mocker): - from openapi_python_client.parser.openapi import Endpoint, Schemas - - schemas = Schemas() - mocker.patch.object(Endpoint, "parse_request_form_body", return_value=(None, schemas)) - mocker.patch.object(Endpoint, "parse_request_json_body", return_value=(mocker.MagicMock(), mocker.MagicMock())) - parse_error = ParseError(data=mocker.MagicMock(), detail=mocker.MagicMock()) - other_schemas = mocker.MagicMock() - mocker.patch.object(Endpoint, "parse_request_binary_body", return_value=(parse_error, other_schemas)) - endpoint = self.make_endpoint() - request_body = mocker.MagicMock() - - result = Endpoint._add_body( - endpoint=endpoint, - data=oai.Operation.model_construct(requestBody=request_body), - schemas=schemas, - config=MagicMock(), - ) - - assert result == ( - ParseError( - header=f"Cannot parse binary request body of endpoint {endpoint.name}", - detail=parse_error.detail, - data=parse_error.data, - ), - other_schemas, - ) - - def test_add_body_bad_form_data(self, enum_property_factory): - from openapi_python_client.parser.openapi import Endpoint, Schemas - - schemas = Schemas( - errors=[ParseError(detail="existing error")], - ) - endpoint = self.make_endpoint() - bad_schema = oai.Schema.model_construct(type=oai.DataType.ARRAY) - - result = Endpoint._add_body( - endpoint=endpoint, - data=oai.Operation.model_construct( - requestBody=oai.RequestBody.model_construct( - content={ - "application/x-www-form-urlencoded": oai.MediaType.model_construct(media_type_schema=bad_schema) - } - ) - ), - schemas=schemas, - config=Config(), - ) - - assert result == ( - ParseError( - detail="type array must have items defined", - header="Cannot parse form request body of endpoint name", - data=bad_schema, - ), - schemas, - ) - - def test_add_body_bad_multipart_data(self, mocker): - from openapi_python_client.parser.openapi import Endpoint, Schemas - - schemas = Schemas() - mocker.patch.object(Endpoint, "parse_request_form_body", return_value=(None, schemas)) - mocker.patch.object(Endpoint, "parse_request_json_body", return_value=(mocker.MagicMock(), mocker.MagicMock())) - parse_error = ParseError(data=mocker.MagicMock(), detail=mocker.MagicMock()) - other_schemas = mocker.MagicMock() - mocker.patch.object(Endpoint, "parse_multipart_body", return_value=(parse_error, other_schemas)) - endpoint = self.make_endpoint() - request_body = mocker.MagicMock() - - result = Endpoint._add_body( - endpoint=endpoint, - data=oai.Operation.model_construct(requestBody=request_body), - schemas=schemas, - config=MagicMock(), - ) - - assert result == ( - ParseError( - header=f"Cannot parse multipart request body of endpoint {endpoint.name}", - detail=parse_error.detail, - data=parse_error.data, - ), - other_schemas, - ) - - def test_add_body_happy(self, mocker): - from openapi_python_client.parser.openapi import Endpoint - from openapi_python_client.parser.properties import Property - - request_body = mocker.MagicMock() - config = mocker.MagicMock() - - form_body = mocker.MagicMock(autospec=Property) - form_body_imports = mocker.MagicMock() - form_body.get_imports.return_value = {form_body_imports} - form_schemas = mocker.MagicMock() - parse_request_form_body = mocker.patch.object( - Endpoint, "parse_request_form_body", return_value=(form_body, form_schemas) - ) - - multipart_body = mocker.MagicMock(autospec=Property) - multipart_body_imports = mocker.MagicMock() - multipart_body.get_imports.return_value = {multipart_body_imports} - multipart_schemas = mocker.MagicMock() - parse_multipart_body = mocker.patch.object( - Endpoint, "parse_multipart_body", return_value=(multipart_body, multipart_schemas) - ) - - json_body = mocker.MagicMock(autospec=Property) - json_body_imports = mocker.MagicMock() - json_body.get_imports.return_value = {json_body_imports} - json_schemas = mocker.MagicMock() - parse_request_json_body = mocker.patch.object( - Endpoint, "parse_request_json_body", return_value=(json_body, json_schemas) - ) - - binary_body = mocker.MagicMock(autospec=Property) - binary_body_imports = mocker.MagicMock() - binary_body.get_imports.return_value = {binary_body_imports} - binary_schemas = mocker.MagicMock() - parse_request_binary_body = mocker.patch.object( - Endpoint, "parse_request_binary_body", return_value=(binary_body, binary_schemas) - ) - - endpoint = self.make_endpoint() - initial_schemas = mocker.MagicMock() - - (endpoint, response_schemas) = Endpoint._add_body( - endpoint=endpoint, - data=oai.Operation.model_construct(requestBody=request_body), - schemas=initial_schemas, - config=config, - ) - - assert response_schemas == multipart_schemas - parse_request_form_body.assert_called_once_with( - body=request_body, schemas=initial_schemas, parent_name="name", config=config - ) - parse_request_json_body.assert_called_once_with( - body=request_body, schemas=form_schemas, parent_name="name", config=config - ) - parse_request_binary_body.assert_called_once_with( - body=request_body, schemas=json_schemas, parent_name="name", config=config - ) - parse_multipart_body.assert_called_once_with( - body=request_body, schemas=binary_schemas, parent_name="name", config=config - ) - form_body.get_imports.assert_called_once_with(prefix="...") - json_body.get_imports.assert_called_once_with(prefix="...") - binary_body.get_imports.assert_called_once_with(prefix="...") - multipart_body.get_imports.assert_called_once_with(prefix="...") - assert endpoint.relative_imports == { - "import_3", - form_body_imports, - json_body_imports, - binary_body_imports, - multipart_body_imports, - } - assert endpoint.json_body == json_body - assert endpoint.form_body == form_body - assert endpoint.multipart_body == multipart_body - assert endpoint.binary_body == binary_body - @pytest.mark.parametrize("response_status_code", ["not_a_number", 499]) def test__add_responses_status_code_error(self, response_status_code, mocker): from openapi_python_client.parser.openapi import Endpoint, Schemas @@ -1088,9 +738,6 @@ def test_from_data_standard(self, mocker): _add_responses = mocker.patch.object( Endpoint, "_add_responses", return_value=(response_endpoint, response_schemas) ) - body_schemas = mocker.MagicMock() - body_endpoint = mocker.MagicMock() - _add_body = mocker.patch.object(Endpoint, "_add_body", return_value=(body_endpoint, body_schemas)) data = oai.Operation.model_construct( description=mocker.MagicMock(), operationId=mocker.MagicMock(), @@ -1103,7 +750,7 @@ def test_from_data_standard(self, mocker): mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=data.description) - endpoint = Endpoint.from_data( + Endpoint.from_data( data=data, path=path, method=method, @@ -1113,8 +760,6 @@ def test_from_data_standard(self, mocker): config=config, ) - assert (endpoint[0], endpoint[1]) == _add_body.return_value - add_parameters.assert_called_once_with( endpoint=Endpoint( path=path, @@ -1133,9 +778,6 @@ def test_from_data_standard(self, mocker): _add_responses.assert_called_once_with( endpoint=param_endpoint, data=data.responses, schemas=param_schemas, config=config ) - _add_body.assert_called_once_with( - endpoint=response_endpoint, data=data, schemas=response_schemas, config=config - ) def test_from_data_no_operation_id(self, mocker): from openapi_python_client.parser.openapi import Endpoint @@ -1148,7 +790,6 @@ def test_from_data_no_operation_id(self, mocker): _add_responses = mocker.patch.object( Endpoint, "_add_responses", return_value=(mocker.MagicMock(), mocker.MagicMock()) ) - _add_body = mocker.patch.object(Endpoint, "_add_body", return_value=(mocker.MagicMock(), mocker.MagicMock())) data = oai.Operation.model_construct( description=mocker.MagicMock(), operationId=None, @@ -1164,8 +805,6 @@ def test_from_data_no_operation_id(self, mocker): data=data, path=path, method=method, tag="default", schemas=schemas, parameters=parameters, config=config ) - assert (endpoint, return_schemas) == _add_body.return_value - add_parameters.assert_called_once_with( endpoint=Endpoint( path=path, @@ -1187,9 +826,6 @@ def test_from_data_no_operation_id(self, mocker): schemas=add_parameters.return_value[1], config=config, ) - _add_body.assert_called_once_with( - endpoint=_add_responses.return_value[0], data=data, schemas=_add_responses.return_value[1], config=config - ) def test_from_data_no_security(self, mocker): from openapi_python_client.parser.openapi import Endpoint @@ -1206,7 +842,6 @@ def test_from_data_no_security(self, mocker): _add_responses = mocker.patch.object( Endpoint, "_add_responses", return_value=(mocker.MagicMock(), mocker.MagicMock()) ) - _add_body = mocker.patch.object(Endpoint, "_add_body", return_value=(mocker.MagicMock(), mocker.MagicMock())) path = mocker.MagicMock() method = mocker.MagicMock() mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=data.description) @@ -1239,10 +874,50 @@ def test_from_data_no_security(self, mocker): schemas=add_parameters.return_value[1], config=config, ) - _add_body.assert_called_once_with( - endpoint=_add_responses.return_value[0], data=data, schemas=_add_responses.return_value[1], config=config + + def test_from_data_some_bad_bodies(self): + endpoint, _, _ = Endpoint.from_data( + data=oai.Operation( + responses={}, + requestBody=oai.RequestBody( + content={ + "application/json": oai.MediaType(media_type_schema=oai.Schema(type=DataType.STRING)), + "not a real media type": oai.MediaType(media_type_schema=oai.Schema(type=DataType.STRING)), + }, + ), + ), + schemas=Schemas(), + config=Config(), + parameters=Parameters(), + tag="tag", + path="/", + method="get", ) + assert isinstance(endpoint, Endpoint) + assert len(endpoint.bodies) == 1 + assert len(endpoint.errors) == 1 + + def test_from_data_all_bodies_bad(self): + endpoint, _, _ = Endpoint.from_data( + data=oai.Operation( + responses={}, + requestBody=oai.RequestBody( + content={ + "not a real media type": oai.MediaType(media_type_schema=oai.Schema(type=DataType.STRING)), + }, + ), + ), + schemas=Schemas(), + config=Config(), + parameters=Parameters(), + tag="tag", + path="/", + method="get", + ) + + assert isinstance(endpoint, ParseError) + @pytest.mark.parametrize( "response_types, expected", (([], "Any"), (["Something"], "Something"), (["First", "Second", "Second"], "Union[First, Second]")),