From 14fb3dfb44f1afa58d8b09853c91db2e79d69913 Mon Sep 17 00:00:00 2001 From: Michael Helmling Date: Fri, 21 Oct 2022 15:22:30 +0200 Subject: [PATCH 1/4] schemas: fix typo --- openapi_python_client/parser/properties/schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi_python_client/parser/properties/schemas.py b/openapi_python_client/parser/properties/schemas.py index a0606b8c1..95d75049d 100644 --- a/openapi_python_client/parser/properties/schemas.py +++ b/openapi_python_client/parser/properties/schemas.py @@ -199,7 +199,7 @@ def parameter_from_reference( parameters: `Parameters` up until now. Returns: - Either the updated `schemas` input or a `PropertyError` if something went wrong. + Either the updated `schemas` input or a `ParameterError` if something went wrong. See Also: - https://swagger.io/docs/specification/using-ref/ From 6105da6fd8278a9b168c748b6a02763b8aa1ad6b Mon Sep 17 00:00:00 2001 From: Michael Helmling Date: Fri, 21 Oct 2022 15:29:27 +0200 Subject: [PATCH 2/4] feat: add support for referenced request bodies --- openapi_python_client/parser/openapi.py | 43 +++++++++++++++---- .../parser/properties/__init__.py | 15 +++++++ .../parser/properties/schemas.py | 9 ++++ 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/openapi_python_client/parser/openapi.py b/openapi_python_client/parser/openapi.py index b6c2a5411..dad7e3fd3 100644 --- a/openapi_python_client/parser/openapi.py +++ b/openapi_python_client/parser/openapi.py @@ -21,10 +21,11 @@ Property, Schemas, build_parameters, + build_request_bodies, build_schemas, property_from_data, ) -from .properties.schemas import parameter_from_reference +from .properties.schemas import RequestBodies, parameter_from_reference from .responses import Response, response_from_data _PATH_PARAM_REGEX = re.compile("{([a-zA-Z_][a-zA-Z0-9_]*)}") @@ -45,7 +46,12 @@ class EndpointCollection: @staticmethod def from_data( - *, data: Dict[str, oai.PathItem], schemas: Schemas, parameters: Parameters, config: Config + *, + data: Dict[str, oai.PathItem], + schemas: Schemas, + parameters: Parameters, + request_bodies: RequestBodies, + config: Config, ) -> Tuple[Dict[utils.PythonIdentifier, "EndpointCollection"], Schemas, Parameters]: """Parse the openapi paths data to get EndpointCollections by tag""" endpoints_by_tag: Dict[utils.PythonIdentifier, EndpointCollection] = {} @@ -66,6 +72,7 @@ def from_data( tag=tag, schemas=schemas, parameters=parameters, + request_bodies=request_bodies, config=config, ) # Add `PathItem` parameters @@ -192,15 +199,27 @@ def _add_body( endpoint: "Endpoint", data: oai.Operation, schemas: Schemas, + request_bodies: RequestBodies, 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): + if data.requestBody is None: return endpoint, schemas - + if isinstance(data.requestBody, oai.Reference): + request_body = request_bodies.bodies_by_reference.get(data.requestBody.ref, None) + if request_body is None: + return ( + ParseError( + header=f"Cannot resolve request body reference {data.requestBody.ref}", + data=data.requestBody, + ), + schemas, + ) + else: + request_body = data.requestBody form_body, schemas = Endpoint.parse_request_form_body( - body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config + body=request_body, schemas=schemas, parent_name=endpoint.name, config=config ) if isinstance(form_body, ParseError): @@ -214,7 +233,7 @@ def _add_body( ) json_body, schemas = Endpoint.parse_request_json_body( - body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config + body=request_body, schemas=schemas, parent_name=endpoint.name, config=config ) if isinstance(json_body, ParseError): return ( @@ -227,7 +246,7 @@ def _add_body( ) multipart_body, schemas = Endpoint.parse_multipart_body( - body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config + body=request_body, schemas=schemas, parent_name=endpoint.name, config=config ) if isinstance(multipart_body, ParseError): return ( @@ -467,6 +486,7 @@ def from_data( tag: str, schemas: Schemas, parameters: Parameters, + request_bodies: RequestBodies, config: Config, ) -> Tuple[Union["Endpoint", ParseError], Schemas, Parameters]: """Construct an endpoint from the OpenAPI data""" @@ -492,7 +512,9 @@ 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) + result, schemas = Endpoint._add_body( + endpoint=result, data=data, schemas=schemas, request_bodies=request_bodies, config=config + ) return result, schemas, parameters @@ -547,12 +569,15 @@ def from_dict(data: Dict[str, Any], *, config: Config) -> Union["GeneratorData", return GeneratorError(header="Failed to parse OpenAPI document", detail=detail) schemas = Schemas() parameters = Parameters() + request_bodies = RequestBodies() if openapi.components and openapi.components.schemas: schemas = build_schemas(components=openapi.components.schemas, schemas=schemas, config=config) if openapi.components and openapi.components.parameters: parameters = build_parameters(components=openapi.components.parameters, parameters=parameters) + if openapi.components and openapi.components.requestBodies: + request_bodies = build_request_bodies(components=openapi.components.requestBodies) endpoint_collections_by_tag, schemas, parameters = EndpointCollection.from_data( - data=openapi.paths, schemas=schemas, parameters=parameters, config=config + data=openapi.paths, schemas=schemas, parameters=parameters, request_bodies=request_bodies, config=config ) enums = (prop for prop in schemas.classes_by_name.values() if isinstance(prop, EnumProperty)) diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index 3eb678c62..27a407b85 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -8,6 +8,7 @@ "Schemas", "build_schemas", "build_parameters", + "build_request_bodies", "property_from_data", ] @@ -19,6 +20,7 @@ from ... import Config from ... import schema as oai from ... import utils +from ...schema import Reference, RequestBody from ..errors import ParameterError, ParseError, PropertyError, ValidationError from .converter import convert, convert_chain from .enum_property import EnumProperty @@ -27,6 +29,7 @@ from .schemas import ( Class, Parameters, + RequestBodies, Schemas, parse_reference_path, update_parameters_with_data, @@ -776,3 +779,15 @@ def build_parameters( parameters.errors.extend(errors) return parameters + + +def build_request_bodies(*, components: Dict[str, Union[RequestBody, Reference]]): + + direct_entries = { + f"#/components/requestBodies/{name}": body for name, body in components.items() if isinstance(body, RequestBody) + } + result = RequestBodies(bodies_by_reference=direct_entries) + ref_entries: Dict[str, Reference] = {name: body for name, body in components.items() if isinstance(body, Reference)} + for name, ref in ref_entries.items(): + result.errors.append(ParseError(detail=f"Unimplemented support for reference request body: {name}")) + return result diff --git a/openapi_python_client/parser/properties/schemas.py b/openapi_python_client/parser/properties/schemas.py index 95d75049d..299b98aa2 100644 --- a/openapi_python_client/parser/properties/schemas.py +++ b/openapi_python_client/parser/properties/schemas.py @@ -16,6 +16,7 @@ from ... import Config from ... import schema as oai +from ...schema import RequestBody from ...schema.openapi_schema_pydantic import Parameter from ...utils import ClassName, PythonIdentifier from ..errors import ParameterError, ParseError, PropertyError @@ -126,6 +127,14 @@ class Parameters: errors: List[ParseError] = attr.ib(factory=list) +@attr.s(auto_attribs=True, frozen=True) +class RequestBodies: + """Structure for containing all defined, shareable, and reusable request bodies""" + + bodies_by_reference: Dict[str, RequestBody] = attr.ib(factory=dict) + errors: List[ParseError] = attr.ib(factory=list) + + def parameter_from_data( *, name: str, From 966be98e0d485ddbb95b76887faa6891cc3921d4 Mon Sep 17 00:00:00 2001 From: Michael Helmling Date: Fri, 21 Oct 2022 15:44:32 +0200 Subject: [PATCH 3/4] fix tests after adding request bodies feature --- tests/test_cli.py | 5 +- tests/test_parser/test_openapi.py | 86 ++++++++++++++++--- .../test_parser/test_properties/test_init.py | 6 +- .../test_properties/test_schemas.py | 2 +- tests/test_parser/test_responses.py | 2 +- 5 files changed, 82 insertions(+), 19 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 1a8752915..61a863ce4 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,7 +4,6 @@ import pytest from typer.testing import CliRunner -from openapi_python_client import Config from openapi_python_client.parser.errors import GeneratorError, ParseError runner = CliRunner() @@ -149,7 +148,7 @@ def test_generate_encoding(self, _create_new_client): def test_generate_encoding_errors(self, _create_new_client): path = "cool/path" file_encoding = "error-file-encoding" - from openapi_python_client.cli import MetaType, app + from openapi_python_client.cli import app result = runner.invoke(app, ["generate", f"--path={path}", f"--file-encoding={file_encoding}"]) @@ -286,7 +285,7 @@ def test_update_encoding(self, _update_existing_client): def test_update_encoding_errors(self, _update_existing_client): path = "cool/path" file_encoding = "error-file-encoding" - from openapi_python_client.cli import MetaType, app + from openapi_python_client.cli import app result = runner.invoke(app, ["update", f"--path={path}", f"--file-encoding={file_encoding}"]) diff --git a/tests/test_parser/test_openapi.py b/tests/test_parser/test_openapi.py index a844e4172..6acbef202 100644 --- a/tests/test_parser/test_openapi.py +++ b/tests/test_parser/test_openapi.py @@ -7,7 +7,7 @@ from openapi_python_client import Config, GeneratorError 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.parser.properties import IntProperty, Parameters, Schemas, RequestBodies MODULE_NAME = "openapi_python_client.parser.openapi" @@ -18,6 +18,7 @@ def test_from_dict(self, mocker, model_property_factory, enum_property_factory): build_schemas = mocker.patch(f"{MODULE_NAME}.build_schemas") build_parameters = mocker.patch(f"{MODULE_NAME}.build_parameters") + build_request_bodies = mocker.patch(f"{MODULE_NAME}.build_request_bodies") EndpointCollection = mocker.patch(f"{MODULE_NAME}.EndpointCollection") schemas = mocker.MagicMock() schemas.classes_by_name = { @@ -48,6 +49,7 @@ def test_from_dict(self, mocker, model_property_factory, enum_property_factory): data=openapi.paths, schemas=build_schemas.return_value, parameters=build_parameters.return_value, + request_bodies=build_request_bodies.return_value, config=config, ) assert generator_data.title == openapi.info.title @@ -279,8 +281,13 @@ def test_add_body_no_data(self, mocker): 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.construct(), schemas=schemas, config=MagicMock()) + Endpoint._add_body( + endpoint=endpoint, + data=oai.Operation.construct(), + schemas=schemas, + request_bodies=RequestBodies(), + config=MagicMock(), + ) parse_request_form_body.assert_not_called() @@ -299,6 +306,7 @@ def test_add_body_bad_json_data(self, mocker): endpoint=endpoint, data=oai.Operation.construct(requestBody=request_body), schemas=schemas, + request_bodies=(RequestBodies()), config=MagicMock(), ) @@ -328,6 +336,7 @@ def test_add_body_bad_form_data(self, enum_property_factory): ) ), schemas=schemas, + request_bodies=RequestBodies(), config=Config(), ) @@ -356,6 +365,7 @@ def test_add_body_bad_multipart_data(self, mocker): endpoint=endpoint, data=oai.Operation.construct(requestBody=request_body), schemas=schemas, + request_bodies=RequestBodies(), config=MagicMock(), ) @@ -406,6 +416,7 @@ def test_add_body_happy(self, mocker): endpoint=endpoint, data=oai.Operation.construct(requestBody=request_body), schemas=initial_schemas, + request_bodies=RequestBodies(), config=config, ) @@ -984,6 +995,7 @@ def test_from_data_bad_params(self, mocker): tag="default", schemas=initial_schemas, parameters=parameters, + request_bodies=RequestBodies(), config=config, ) @@ -1019,6 +1031,7 @@ def test_from_data_bad_responses(self, mocker): tag="default", schemas=initial_schemas, parameters=initial_parameters, + request_bodies=RequestBodies(), config=config, ) @@ -1051,6 +1064,7 @@ def test_from_data_standard(self, mocker): ) initial_schemas = mocker.MagicMock() initial_parameters = mocker.MagicMock() + request_bodies = RequestBodies() config = MagicMock() mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=data.description) @@ -1062,6 +1076,7 @@ def test_from_data_standard(self, mocker): tag="default", schemas=initial_schemas, parameters=initial_parameters, + request_bodies=request_bodies, config=config, ) @@ -1086,7 +1101,11 @@ def test_from_data_standard(self, mocker): 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 + endpoint=response_endpoint, + data=data, + schemas=response_schemas, + request_bodies=request_bodies, + config=config, ) def test_from_data_no_operation_id(self, mocker): @@ -1111,9 +1130,17 @@ def test_from_data_no_operation_id(self, mocker): mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=data.description) config = MagicMock() parameters = mocker.MagicMock() + request_bodies = mocker.MagicMock() endpoint, return_schemas, return_params = Endpoint.from_data( - data=data, path=path, method=method, tag="default", schemas=schemas, parameters=parameters, config=config + data=data, + path=path, + method=method, + tag="default", + schemas=schemas, + parameters=parameters, + request_bodies=request_bodies, + config=config, ) assert (endpoint, return_schemas) == _add_body.return_value @@ -1140,7 +1167,11 @@ def test_from_data_no_operation_id(self, mocker): config=config, ) _add_body.assert_called_once_with( - endpoint=_add_responses.return_value[0], data=data, schemas=_add_responses.return_value[1], config=config + endpoint=_add_responses.return_value[0], + data=data, + schemas=_add_responses.return_value[1], + request_bodies=request_bodies, + config=config, ) def test_from_data_no_security(self, mocker): @@ -1164,10 +1195,18 @@ def test_from_data_no_security(self, mocker): mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=data.description) schemas = mocker.MagicMock() parameters = mocker.MagicMock() + request_bodies = mocker.MagicMock() config = MagicMock() Endpoint.from_data( - data=data, path=path, method=method, tag="a", schemas=schemas, parameters=parameters, config=config + data=data, + path=path, + method=method, + tag="a", + schemas=schemas, + parameters=parameters, + request_bodies=request_bodies, + config=config, ) add_parameters.assert_called_once_with( @@ -1192,7 +1231,11 @@ def test_from_data_no_security(self, mocker): config=config, ) _add_body.assert_called_once_with( - endpoint=_add_responses.return_value[0], data=data, schemas=_add_responses.return_value[1], config=config + endpoint=_add_responses.return_value[0], + data=data, + schemas=_add_responses.return_value[1], + request_bodies=request_bodies, + config=config, ) @pytest.mark.parametrize( @@ -1261,9 +1304,12 @@ def test_from_data(self, mocker): ) schemas = mocker.MagicMock() parameters = mocker.MagicMock() + request_bodies = mocker.MagicMock() config = MagicMock() - result = EndpointCollection.from_data(data=data, schemas=schemas, parameters=parameters, config=config) + result = EndpointCollection.from_data( + data=data, schemas=schemas, parameters=parameters, request_bodies=request_bodies, config=config + ) endpoint_from_data.assert_has_calls( [ @@ -1274,6 +1320,7 @@ def test_from_data(self, mocker): tag="default", schemas=schemas, parameters=parameters, + request_bodies=request_bodies, config=config, ), mocker.call( @@ -1283,6 +1330,7 @@ def test_from_data(self, mocker): tag="tag_2", schemas=schemas_1, parameters=parameters_1, + request_bodies=request_bodies, config=config, ), mocker.call( @@ -1292,6 +1340,7 @@ def test_from_data(self, mocker): tag="default", schemas=schemas_2, parameters=parameters_2, + request_bodies=request_bodies, config=config, ), ], @@ -1328,6 +1377,7 @@ def test_from_data_overrides_path_item_params_with_operation_params(self): data=data, schemas=Schemas(), parameters=Parameters(), + request_bodies=RequestBodies(), config=Config(), ) collection: EndpointCollection = collections["default"] @@ -1349,6 +1399,7 @@ def test_from_data_errors(self, mocker): parameters_1 = mocker.MagicMock() parameters_2 = mocker.MagicMock() parameters_3 = mocker.MagicMock() + request_bodies = mocker.MagicMock() endpoint_from_data = mocker.patch.object( Endpoint, "from_data", @@ -1363,7 +1414,11 @@ def test_from_data_errors(self, mocker): config = MagicMock() result, result_schemas, result_parameters = EndpointCollection.from_data( - data=data, schemas=schemas, config=config, parameters=parameters + data=data, + schemas=schemas, + config=config, + parameters=parameters, + request_bodies=request_bodies, ) endpoint_from_data.assert_has_calls( @@ -1375,6 +1430,7 @@ def test_from_data_errors(self, mocker): tag="default", schemas=schemas, parameters=parameters, + request_bodies=request_bodies, config=config, ), mocker.call( @@ -1384,6 +1440,7 @@ def test_from_data_errors(self, mocker): tag="tag_2", schemas=schemas_1, parameters=parameters_1, + request_bodies=request_bodies, config=config, ), mocker.call( @@ -1393,6 +1450,7 @@ def test_from_data_errors(self, mocker): tag="default", schemas=schemas_2, parameters=parameters_2, + request_bodies=request_bodies, config=config, ), ], @@ -1434,9 +1492,12 @@ def test_from_data_tags_snake_case_sanitizer(self, mocker): ) schemas = mocker.MagicMock() parameters = mocker.MagicMock() + request_bodies = mocker.MagicMock() config = MagicMock() - result = EndpointCollection.from_data(data=data, schemas=schemas, parameters=parameters, config=config) + result = EndpointCollection.from_data( + data=data, schemas=schemas, parameters=parameters, request_bodies=request_bodies, config=config + ) endpoint_from_data.assert_has_calls( [ @@ -1447,6 +1508,7 @@ def test_from_data_tags_snake_case_sanitizer(self, mocker): tag="default", schemas=schemas, parameters=parameters, + request_bodies=request_bodies, config=config, ), mocker.call( @@ -1456,6 +1518,7 @@ def test_from_data_tags_snake_case_sanitizer(self, mocker): tag="amf_subscription_info_document", schemas=schemas_1, parameters=parameters_1, + request_bodies=request_bodies, config=config, ), mocker.call( @@ -1465,6 +1528,7 @@ def test_from_data_tags_snake_case_sanitizer(self, mocker): tag="tag3_abc", schemas=schemas_2, parameters=parameters_2, + request_bodies=request_bodies, config=config, ), ], diff --git a/tests/test_parser/test_properties/test_init.py b/tests/test_parser/test_properties/test_init.py index 3c063365e..3b8ad7d11 100644 --- a/tests/test_parser/test_properties/test_init.py +++ b/tests/test_parser/test_properties/test_init.py @@ -338,7 +338,7 @@ def test_property_from_data_str_enum_with_null(self, enum_property_factory): } def test_property_from_data_null_enum(self, enum_property_factory, none_property_factory): - from openapi_python_client.parser.properties import Class, Schemas, property_from_data + from openapi_python_client.parser.properties import Schemas, property_from_data from openapi_python_client.schema import Schema data = Schema(title="AnEnumWithOnlyNull", enum=[None], nullable=False, default=None) @@ -459,7 +459,7 @@ def test_property_from_data_ref_enum_with_invalid_default(self, enum_property_fa assert prop == PropertyError(data=data, detail="x is an invalid default for enum MyEnum") def test_property_from_data_ref_model(self, model_property_factory): - from openapi_python_client.parser.properties import Class, ModelProperty, Schemas, property_from_data + from openapi_python_client.parser.properties import Class, Schemas, property_from_data name = "new_name" required = False @@ -646,7 +646,7 @@ def test_property_from_data_union(self, mocker): ) def test_property_from_data_union_of_one_element(self, mocker, model_property_factory): - from openapi_python_client.parser.properties import Class, ModelProperty, Schemas, property_from_data + from openapi_python_client.parser.properties import Schemas, property_from_data name = "new_name" required = False diff --git a/tests/test_parser/test_properties/test_schemas.py b/tests/test_parser/test_properties/test_schemas.py index 629286cae..cafb47a70 100644 --- a/tests/test_parser/test_properties/test_schemas.py +++ b/tests/test_parser/test_properties/test_schemas.py @@ -57,7 +57,7 @@ def test_cannot_parse_parameters_by_reference(self): def test_parameters_without_schema_are_ignored(self): from openapi_python_client.parser.properties import Parameters from openapi_python_client.parser.properties.schemas import parameter_from_data - from openapi_python_client.schema import ParameterLocation, Schema + from openapi_python_client.schema import ParameterLocation param = Parameter(name="a_schemaless_param", param_in=ParameterLocation.QUERY) parameters = Parameters() diff --git a/tests/test_parser/test_responses.py b/tests/test_parser/test_responses.py index ab73cfb74..b8c5f26d4 100644 --- a/tests/test_parser/test_responses.py +++ b/tests/test_parser/test_responses.py @@ -2,7 +2,7 @@ import openapi_python_client.schema as oai from openapi_python_client.parser.errors import ParseError, PropertyError -from openapi_python_client.parser.properties import AnyProperty, Schemas, StringProperty +from openapi_python_client.parser.properties import Schemas MODULE_NAME = "openapi_python_client.parser.responses" From 87969ab17d782b0e1bfbeb0aad54a65cc55c54c7 Mon Sep 17 00:00:00 2001 From: Michael Helmling Date: Fri, 21 Oct 2022 16:03:40 +0200 Subject: [PATCH 4/4] add e2e test for referenced request body --- .../my_test_api_client/api/tests/__init__.py | 8 ++ .../api/tests/post_form_data_ref.py | 87 ++++++++++++ end_to_end_tests/openapi.json | 127 +++++++++++++----- 3 files changed, 192 insertions(+), 30 deletions(-) create mode 100644 end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data_ref.py diff --git a/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py index 13120943a..1fadd2a80 100644 --- a/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py +++ b/end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py @@ -16,6 +16,7 @@ octet_stream_tests_octet_stream_get, post_form_data, post_form_data_inline, + post_form_data_ref, post_tests_json_body_string, test_inline_objects, token_with_cookie_auth_token_with_cookie_get, @@ -68,6 +69,13 @@ def post_form_data(cls) -> types.ModuleType: """ return post_form_data + @classmethod + def post_form_data_ref(cls) -> types.ModuleType: + """ + Post form data (ref request body) + """ + return post_form_data_ref + @classmethod def post_form_data_inline(cls) -> types.ModuleType: """ diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data_ref.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data_ref.py new file mode 100644 index 000000000..d68fe0aaa --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data_ref.py @@ -0,0 +1,87 @@ +from http import HTTPStatus +from typing import Any, Dict + +import httpx + +from ...client import Client +from ...models.a_form_data import AFormData +from ...types import Response + + +def _get_kwargs( + *, + client: Client, + form_data: AFormData, +) -> Dict[str, Any]: + url = "{}/tests/post_form_data_ref_body".format(client.base_url) + + headers: Dict[str, str] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() + + return { + "method": "post", + "url": url, + "headers": headers, + "cookies": cookies, + "timeout": client.get_timeout(), + "data": form_data.to_dict(), + } + + +def _build_response(*, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=None, + ) + + +def sync_detailed( + *, + client: Client, + form_data: AFormData, +) -> Response[Any]: + """Post form data (ref request body) + + Post form data (ref request body) + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + client=client, + form_data=form_data, + ) + + response = httpx.request( + verify=client.verify_ssl, + **kwargs, + ) + + return _build_response(response=response) + + +async def asyncio_detailed( + *, + client: Client, + form_data: AFormData, +) -> Response[Any]: + """Post form data (ref request body) + + Post form data (ref request body) + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + client=client, + form_data=form_data, + ) + + async with httpx.AsyncClient(verify=client.verify_ssl) as _client: + response = await _client.request(**kwargs) + + return _build_response(response=response) diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 8298670fd..b1d711f91 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -242,6 +242,29 @@ } } }, + "/tests/post_form_data_ref_body": { + "post": { + "tags": [ + "tests" + ], + "summary": "Post form data (ref request body)", + "description": "Post form data (ref request body)", + "operationId": "post_form_data_ref", + "requestBody": { + "$ref": "#/components/requestBodies/AFormBody" + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, "/tests/post_form_data_inline": { "post": { "tags": [ @@ -756,7 +779,9 @@ }, "/responses/unions/simple_before_complex": { "post": { - "tags": ["responses"], + "tags": [ + "responses" + ], "description": "Regression test for #603", "responses": { "200": { @@ -765,12 +790,18 @@ "application/json": { "schema": { "type": "object", - "required": ["a"], + "required": [ + "a" + ], "properties": { "a": { "oneOf": [ - {"type": "string"}, - {"type": "object"} + { + "type": "string" + }, + { + "type": "object" + } ] } } @@ -877,20 +908,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}": { @@ -939,7 +970,9 @@ }, "/tag_with_number": { "get": { - "tags": ["1"], + "tags": [ + "1" + ], "responses": { "200": { "description": "Success" @@ -1163,9 +1196,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": { @@ -1477,7 +1516,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": { @@ -1519,7 +1562,10 @@ "some_object": { "title": "Some Object", "type": "object", - "required": ["num", "text"], + "required": [ + "num", + "text" + ], "properties": { "num": { "type": "number" @@ -1532,7 +1578,9 @@ "some_optional_object": { "title": "Some Optional Object", "type": "object", - "required": ["foo"], + "required": [ + "foo" + ], "properties": { "foo": { "type": "string" @@ -1755,7 +1803,10 @@ }, "type_enum": { "type": "integer", - "enum": [0, 1] + "enum": [ + 0, + 1 + ] } } }, @@ -1768,11 +1819,15 @@ }, "type": { "type": "string", - "enum": ["submodel"] + "enum": [ + "submodel" + ] }, "type_enum": { "type": "integer", - "enum": [0] + "enum": [ + 0 + ] } } }, @@ -1915,7 +1970,7 @@ } } }, - "ModelWithDateTimeProperty" : { + "ModelWithDateTimeProperty": { "type": "object", "properties": { "datetime": { @@ -2093,10 +2148,10 @@ "type": "string", "format": "byte" }, - "import": { + "import": { "type": "object" }, - "None": { + "None": { "type": "object" }, "model.reference.with.Periods": { @@ -2167,6 +2222,18 @@ "type": "string" } } + }, + "requestBodies": { + "AFormBody": { + "required": true, + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/AFormData" + } + } + } + } } } }