Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[python-experimental] Allow response media types to omit schema #12135

Merged
merged 10 commits into from
Apr 13, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -6753,7 +6753,10 @@ protected LinkedHashMap<String, CodegenMediaType> getContent(Content content, Se
}
}
String contentType = contentEntry.getKey();
CodegenProperty schemaProp = fromProperty(toMediaTypeSchemaName(contentType, mediaTypeSchemaSuffix), mt.getSchema());
CodegenProperty schemaProp = null;
if (mt.getSchema() != null) {
schemaProp = fromProperty(toMediaTypeSchemaName(contentType, mediaTypeSchemaSuffix), mt.getSchema());
}
CodegenMediaType codegenMt = new CodegenMediaType(schemaProp, ceMap);
cmtContent.put(contentType, codegenMt);
if (schemaProp != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,7 @@ class Encoding:
self.allow_reserved = allow_reserved


@dataclass
class MediaType:
"""
Used to store request and response body schema information
Expand All @@ -682,14 +683,8 @@ class MediaType:
The encoding object SHALL only apply to requestBody objects when the media type is
multipart or application/x-www-form-urlencoded.
"""

def __init__(
self,
schema: typing.Type[Schema],
encoding: typing.Optional[typing.Dict[str, Encoding]] = None,
):
self.schema = schema
self.encoding = encoding
schema: typing.Optional[typing.Type[Schema]] = None
encoding: typing.Optional[typing.Dict[str, Encoding]] = None


@dataclass
Expand Down Expand Up @@ -808,7 +803,27 @@ class OpenApiResponse(JSONDetector):
content_type = response.getheader('content-type')
deserialized_body = unset
streamed = response.supports_chunked_reads()

deserialized_headers = unset
if self.headers is not None:
# TODO add header deserialiation here
pass

if self.content is not None:
if content_type not in self.content:
raise ApiValueError(
f'Invalid content_type={content_type} returned for response with '
'status_code={str(response.status)}'
)
body_schema = self.content[content_type].schema
if body_schema is None:
# some specs do not define response content media type schemas
return self.response_cls(
response=response,
headers=deserialized_headers,
body=unset
)

if self.content_type_is_json(content_type):
body_data = self.__deserialize_json(response)
elif content_type == 'application/octet-stream':
Expand All @@ -818,16 +833,11 @@ class OpenApiResponse(JSONDetector):
content_type = 'multipart/form-data'
else:
raise NotImplementedError('Deserialization of {} has not yet been implemented'.format(content_type))
body_schema = self.content[content_type].schema
deserialized_body = body_schema._from_openapi_data(
body_data, _configuration=configuration)
elif streamed:
response.release_conn()

deserialized_headers = unset
if self.headers is not None:
deserialized_headers = unset

return self.response_cls(
response=response,
headers=deserialized_headers,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ default | ApiResponseForDefault | {{message}}
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
response | urllib3.HTTPResponse | Raw response |
body | {{#unless content}}Unset{{else}}typing.Union[{{#each content}}{{this.schema.baseName}}, {{/each}}]{{/unless}} | {{#unless content}}body was not defined{{/unless}} |
body | {{#unless content}}Unset{{else}}typing.Union[{{#each content}}{{#if this.schema}}{{this.schema.baseName}}{{else}}Unset{{/if}}, {{/each}}]{{/unless}} | {{#unless content}}body was not defined{{/unless}} |
headers | {{#unless responseHeaders}}Unset{{else}}ResponseHeadersFor{{code}}{{/unless}} | {{#unless responseHeaders}}headers were not defined{{/unless}} |
{{#each content}}
{{#with this.schema}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ class RequestCookieParams(RequestRequiredCookieParams, RequestOptionalCookiePara
request_body_{{paramName}} = api_client.RequestBody(
content={
{{#each content}}
'{{{@key}}}': api_client.MediaType(
schema={{this.schema.baseName}}),
'{{{@key}}}': api_client.MediaType({{#if this.schema}}
schema={{this.schema.baseName}}{{/if}}),
{{/each}}
},
{{#if required}}
Expand Down Expand Up @@ -285,7 +285,11 @@ class ApiResponseFor{{code}}(api_client.ApiResponse):
{{#and responseHeaders content}}
body: typing.Union[
{{#each content}}
{{#if this.schema}}
{{this.schema.baseName}},
{{else}}
Unset,
{{/if}}
{{/each}}
]
headers: ResponseHeadersFor{{code}}
Expand All @@ -297,7 +301,11 @@ class ApiResponseFor{{code}}(api_client.ApiResponse):
{{else}}
body: typing.Union[
{{#each content}}
{{#if this.schema}}
{{this.schema.baseName}},
{{else}}
Unset,
{{/if}}
{{/each}}
]
headers: Unset = unset
Expand All @@ -323,8 +331,8 @@ _response_for_{{code}} = api_client.OpenApiResponse(
{{#if @first}}
content={
{{/if}}
'{{{@key}}}': api_client.MediaType(
schema={{this.schema.baseName}}),
'{{{@key}}}': api_client.MediaType({{#if this.schema}}
schema={{this.schema.baseName}}{{/if}}),
{{#if @last}}
},
{{/if}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1546,6 +1546,18 @@ paths:
content:
application/json; charset=utf-8:
schema: {}
"/fake/responseWithoutSchema":
get:
tags:
- fake
summary: receives a response without schema
operationId: responseWithoutSchema
responses:
'200':
description: contents without schema definition
content:
application/json: {}
application/xml: {}
servers:
- url: 'http://{server}.swagger.io:{port}/v2'
description: petstore server
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Class | Method | HTTP request | Description
*FakeApi* | [**parameter_collisions**](docs/FakeApi.md#parameter_collisions) | **POST** /fake/parameterCollisions/{1}/{aB}/{Ab}/{self}/{A-B}/ | parameter collision case
*FakeApi* | [**query_parameter_collection_format**](docs/FakeApi.md#query_parameter_collection_format) | **PUT** /fake/test-query-paramters |
*FakeApi* | [**ref_object_in_query**](docs/FakeApi.md#ref_object_in_query) | **GET** /fake/refObjInQuery | user list
*FakeApi* | [**response_without_schema**](docs/FakeApi.md#response_without_schema) | **GET** /fake/responseWithoutSchema | receives a response without schema
*FakeApi* | [**string**](docs/FakeApi.md#string) | **POST** /fake/refs/string |
*FakeApi* | [**string_enum**](docs/FakeApi.md#string_enum) | **POST** /fake/refs/enum |
*FakeApi* | [**upload_download_file**](docs/FakeApi.md#upload_download_file) | **POST** /fake/uploadDownloadFile | uploads a file and downloads a file using application/octet-stream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Method | HTTP request | Description
[**parameter_collisions**](FakeApi.md#parameter_collisions) | **POST** /fake/parameterCollisions/{1}/{aB}/{Ab}/{self}/{A-B}/ | parameter collision case
[**query_parameter_collection_format**](FakeApi.md#query_parameter_collection_format) | **PUT** /fake/test-query-paramters |
[**ref_object_in_query**](FakeApi.md#ref_object_in_query) | **GET** /fake/refObjInQuery | user list
[**response_without_schema**](FakeApi.md#response_without_schema) | **GET** /fake/responseWithoutSchema | receives a response without schema
[**string**](FakeApi.md#string) | **POST** /fake/refs/string |
[**string_enum**](FakeApi.md#string_enum) | **POST** /fake/refs/enum |
[**upload_download_file**](FakeApi.md#upload_download_file) | **POST** /fake/uploadDownloadFile | uploads a file and downloads a file using application/octet-stream
Expand Down Expand Up @@ -2547,6 +2548,61 @@ body | Unset | body was not defined |
headers | Unset | headers were not defined |


void (empty response body)

### Authorization

No authorization required

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

# **response_without_schema**
> response_without_schema()

receives a response without schema

### Example

```python
import petstore_api
from petstore_api.api import fake_api
from pprint import pprint
# Defining the host is optional and defaults to http://petstore.swagger.io:80/v2
# See configuration.py for a list of all supported configuration parameters.
configuration = petstore_api.Configuration(
host = "http://petstore.swagger.io:80/v2"
)

# Enter a context with an instance of the API client
with petstore_api.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = fake_api.FakeApi(api_client)

# example, this endpoint has no required or optional parameters
try:
# receives a response without schema
api_response = api_instance.response_without_schema()
except petstore_api.ApiException as e:
print("Exception when calling FakeApi->response_without_schema: %s\n" % e)
```
### Parameters
This endpoint does not need any parameter.

### Return Types, Responses

Code | Class | Description
------------- | ------------- | -------------
n/a | api_client.ApiResponseWithoutDeserialization | When skip_deserialization is True this response is returned
200 | ApiResponseFor200 | contents without schema definition

#### ApiResponseFor200
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
response | urllib3.HTTPResponse | Raw response |
body | typing.Union[Unset, Unset, ] | |
headers | Unset | headers were not defined |


void (empty response body)

### Authorization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from petstore_api.api.fake_api_endpoints.parameter_collisions import ParameterCollisions
from petstore_api.api.fake_api_endpoints.query_parameter_collection_format import QueryParameterCollectionFormat
from petstore_api.api.fake_api_endpoints.ref_object_in_query import RefObjectInQuery
from petstore_api.api.fake_api_endpoints.response_without_schema import ResponseWithoutSchema
from petstore_api.api.fake_api_endpoints.string import String
from petstore_api.api.fake_api_endpoints.string_enum import StringEnum
from petstore_api.api.fake_api_endpoints.upload_download_file import UploadDownloadFile
Expand Down Expand Up @@ -66,6 +67,7 @@ class FakeApi(
ParameterCollisions,
QueryParameterCollectionFormat,
RefObjectInQuery,
ResponseWithoutSchema,
String,
StringEnum,
UploadDownloadFile,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# coding: utf-8

"""


Generated by: https://openapi-generator.tech
"""

from dataclasses import dataclass
import re # noqa: F401
import sys # noqa: F401
import typing
import urllib3
from urllib3._collections import HTTPHeaderDict

from petstore_api import api_client, exceptions
import decimal # noqa: F401
from datetime import date, datetime # noqa: F401
from frozendict import frozendict # noqa: F401

from petstore_api.schemas import ( # noqa: F401
AnyTypeSchema,
ComposedSchema,
DictSchema,
ListSchema,
StrSchema,
IntSchema,
Int32Schema,
Int64Schema,
Float32Schema,
Float64Schema,
NumberSchema,
DateSchema,
DateTimeSchema,
DecimalSchema,
BoolSchema,
BinarySchema,
NoneSchema,
none_type,
Configuration,
Unset,
unset,
ComposedBase,
ListBase,
DictBase,
NoneBase,
StrBase,
IntBase,
Int32Base,
Int64Base,
Float32Base,
Float64Base,
NumberBase,
DateBase,
DateTimeBase,
BoolBase,
BinaryBase,
Schema,
_SchemaValidator,
_SchemaTypeChecker,
_SchemaEnumMaker
)

_path = '/fake/responseWithoutSchema'
_method = 'GET'


@dataclass
class ApiResponseFor200(api_client.ApiResponse):
response: urllib3.HTTPResponse
body: typing.Union[
Unset,
Unset,
]
headers: Unset = unset


_response_for_200 = api_client.OpenApiResponse(
response_cls=ApiResponseFor200,
content={
'application/json': api_client.MediaType(),
'application/xml': api_client.MediaType(),
},
)
_status_code_to_response = {
'200': _response_for_200,
}
_all_accept_content_types = (
'application/json',
'application/xml',
)


class ResponseWithoutSchema(api_client.Api):

def response_without_schema(
self: api_client.Api,
accept_content_types: typing.Tuple[str] = _all_accept_content_types,
stream: bool = False,
timeout: typing.Optional[typing.Union[int, typing.Tuple]] = None,
skip_deserialization: bool = False,
) -> typing.Union[
ApiResponseFor200,
api_client.ApiResponseWithoutDeserialization
]:
"""
receives a response without schema
:param skip_deserialization: If true then api_response.response will be set but
api_response.body and api_response.headers will not be deserialized into schema
class instances
"""

_headers = HTTPHeaderDict()
# TODO add cookie handling
if accept_content_types:
for accept_content_type in accept_content_types:
_headers.add('Accept', accept_content_type)

response = self.api_client.call_api(
resource_path=_path,
method=_method,
headers=_headers,
stream=stream,
timeout=timeout,
)

if skip_deserialization:
api_response = api_client.ApiResponseWithoutDeserialization(response=response)
else:
response_for_status = _status_code_to_response.get(str(response.status))
if response_for_status:
api_response = response_for_status.deserialize(response, self.api_client.configuration)
else:
api_response = api_client.ApiResponseWithoutDeserialization(response=response)

if not 200 <= response.status <= 299:
raise exceptions.ApiException(api_response=api_response)

return api_response
Loading