diff --git a/.changeset/add_original_openapi_data_attribute_to_response_object.md b/.changeset/add_original_openapi_data_attribute_to_response_object.md new file mode 100644 index 000000000..61ccf8de5 --- /dev/null +++ b/.changeset/add_original_openapi_data_attribute_to_response_object.md @@ -0,0 +1,10 @@ +--- +default: minor +--- + +# Add original OpenAPI `data` attribute to `Response` object + +PR #767 + +In custom templates, you can now access a `response.data` attribute that contains the original OpenAPI definition of the +response (Response Object or Reference Object). diff --git a/openapi_python_client/parser/responses.py b/openapi_python_client/parser/responses.py index a8350777f..3a22deb71 100644 --- a/openapi_python_client/parser/responses.py +++ b/openapi_python_client/parser/responses.py @@ -34,6 +34,7 @@ class Response: status_code: HTTPStatus prop: Property source: _ResponseSource + data: Union[oai.Response, oai.Reference] # Original data which created this response, useful for custom templates def _source_by_content_type(content_type: str) -> Optional[_ResponseSource]: @@ -60,17 +61,18 @@ def empty_response( status_code: HTTPStatus, response_name: str, config: Config, - description: Optional[str], + data: Union[oai.Response, oai.Reference], ) -> Response: """Return an untyped response, for when no response type is defined""" return Response( + data=data, status_code=status_code, prop=AnyProperty( name=response_name, default=None, required=True, python_name=PythonIdentifier(value=response_name, prefix=config.field_prefix), - description=description, + description=data.description if isinstance(data, oai.Response) else None, example=None, ), source=NONE_SOURCE, @@ -94,7 +96,7 @@ def response_from_data( status_code=status_code, response_name=response_name, config=config, - description=None, + data=data, ), schemas, ) @@ -106,7 +108,7 @@ def response_from_data( status_code=status_code, response_name=response_name, config=config, - description=data.description, + data=data, ), schemas, ) @@ -128,7 +130,7 @@ def response_from_data( status_code=status_code, response_name=response_name, config=config, - description=data.description, + data=data, ), schemas, ) @@ -145,4 +147,4 @@ def response_from_data( if isinstance(prop, PropertyError): return prop, schemas - return Response(status_code=status_code, prop=prop, source=source), schemas + return Response(status_code=status_code, prop=prop, source=source, data=data), schemas diff --git a/tests/test_parser/test_openapi.py b/tests/test_parser/test_openapi.py index a92cc7845..d81c57556 100644 --- a/tests/test_parser/test_openapi.py +++ b/tests/test_parser/test_openapi.py @@ -187,55 +187,6 @@ def test__add_responses_error(self, mocker): ), ] - def test__add_responses(self, mocker, date_time_property_factory, date_property_factory): - from openapi_python_client.parser.openapi import Endpoint, Response - - response_1_data = mocker.MagicMock() - response_2_data = mocker.MagicMock() - data = { - "200": response_1_data, - "404": response_2_data, - } - endpoint = self.make_endpoint() - schemas = mocker.MagicMock() - schemas_1 = mocker.MagicMock() - schemas_2 = mocker.MagicMock() - response_1 = Response( - status_code=200, - source="source", - prop=date_time_property_factory(name="datetime"), - ) - response_2 = Response( - status_code=404, - source="source", - prop=date_property_factory(name="date"), - ) - response_from_data = mocker.patch( - f"{MODULE_NAME}.response_from_data", side_effect=[(response_1, schemas_1), (response_2, schemas_2)] - ) - config = MagicMock() - - endpoint, response_schemas = Endpoint._add_responses( - endpoint=endpoint, data=data, schemas=schemas, config=config - ) - - response_from_data.assert_has_calls( - [ - mocker.call(status_code=200, data=response_1_data, schemas=schemas, parent_name="name", config=config), - mocker.call( - status_code=404, data=response_2_data, schemas=schemas_1, parent_name="name", config=config - ), - ] - ) - assert endpoint.responses == [response_1, response_2] - assert endpoint.relative_imports == { - "from dateutil.parser import isoparse", - "from typing import cast", - "import datetime", - "import_3", - } - assert response_schemas == schemas_2 - def test_add_parameters_handles_no_params(self): from openapi_python_client.parser.openapi import Endpoint, Schemas diff --git a/tests/test_parser/test_responses.py b/tests/test_parser/test_responses.py index c60b23a72..0342112c5 100644 --- a/tests/test_parser/test_responses.py +++ b/tests/test_parser/test_responses.py @@ -11,9 +11,11 @@ def test_response_from_data_no_content(any_property_factory): from openapi_python_client.parser.responses import Response, response_from_data + data = oai.Response.model_construct(description="") + response, schemas = response_from_data( status_code=200, - data=oai.Response.model_construct(description=""), + data=data, schemas=Schemas(), parent_name="parent", config=MagicMock(), @@ -28,15 +30,18 @@ def test_response_from_data_no_content(any_property_factory): description="", ), source=NONE_SOURCE, + data=data, ) def test_response_from_data_reference(any_property_factory): from openapi_python_client.parser.responses import Response, response_from_data + data = oai.Reference.model_construct() + response, schemas = response_from_data( status_code=200, - data=oai.Reference.model_construct(), + data=data, schemas=Schemas(), parent_name="parent", config=MagicMock(), @@ -50,6 +55,7 @@ def test_response_from_data_reference(any_property_factory): required=True, ), source=NONE_SOURCE, + data=data, ) @@ -92,6 +98,7 @@ def test_response_from_data_no_content_schema(any_property_factory): description=data.description, ), source=NONE_SOURCE, + data=data, ) @@ -147,6 +154,7 @@ def test_response_from_data_property(mocker, any_property_factory): status_code=400, prop=prop, source=JSON_SOURCE, + data=data, ) property_from_data.assert_called_once_with( name="response_400",