Skip to content

Commit

Permalink
[python-nextgen] Add ApiResponse object (#15367)
Browse files Browse the repository at this point in the history
* add ApiResponse object

* fix tests

* improve api response

* add back _preload_content, add tests
  • Loading branch information
wing328 authored May 3, 2023
1 parent bec32ae commit 021d3a3
Show file tree
Hide file tree
Showing 38 changed files with 1,343 additions and 1,317 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ public void processOpts() {
}

supportingFiles.add(new SupportingFile("api_client.mustache", packagePath(), "api_client.py"));
supportingFiles.add(new SupportingFile("api_response.mustache", packagePath(), "api_response.py"));

if ("asyncio".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("asyncio/rest.mustache", packagePath(), "rest.py"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ __version__ = "{{packageVersion}}"
{{#apiInfo}}{{#apis}}from {{apiPackage}}.{{classFilename}} import {{classname}}
{{/apis}}{{/apiInfo}}
# import ApiClient
from {{packageName}}.api_response import ApiResponse
from {{packageName}}.api_client import ApiClient
from {{packageName}}.configuration import Configuration
from {{packageName}}.exceptions import OpenApiException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ from typing import overload, Optional, Union, Awaitable{{/asyncio}}
{{/imports}}

from {{packageName}}.api_client import ApiClient
from {{packageName}}.api_response import ApiResponse
from {{packageName}}.exceptions import ( # noqa: F401
ApiTypeError,
ApiValueError
Expand Down Expand Up @@ -63,10 +64,6 @@ class {{classname}}(object):
{{/allParams}}
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _preload_content: if False, the urllib3.HTTPResponse object will
be returned without reading/decoding response
data. Default is True.
:type _preload_content: bool, optional
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
Expand All @@ -77,14 +74,16 @@ class {{classname}}(object):
:rtype: {{returnType}}{{^returnType}}None{{/returnType}}
"""
kwargs['_return_http_data_only'] = True
if '_preload_content' in kwargs:
raise ValueError("Error! Please call the {{operationId}}_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data")
{{#asyncio}}
if async_req is not None:
kwargs['async_req'] = async_req
{{/asyncio}}
return self.{{operationId}}_with_http_info({{#allParams}}{{paramName}}, {{/allParams}}**kwargs) # noqa: E501

@validate_arguments
def {{operationId}}_with_http_info(self, {{#allParams}}{{paramName}} : {{{vendorExtensions.x-py-typing}}}{{^required}} = None{{/required}}, {{/allParams}}**kwargs): # noqa: E501
def {{operationId}}_with_http_info(self, {{#allParams}}{{paramName}} : {{{vendorExtensions.x-py-typing}}}{{^required}} = None{{/required}}, {{/allParams}}**kwargs) -> ApiResponse: # noqa: E501
"""{{{summary}}}{{^summary}}{{operationId}}{{/summary}} # noqa: E501

{{#notes}}
Expand All @@ -102,13 +101,14 @@ class {{classname}}(object):
{{/allParams}}
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _return_http_data_only: response data without head status code
and headers
:type _return_http_data_only: bool, optional
:param _preload_content: if False, the urllib3.HTTPResponse object will
be returned without reading/decoding response
data. Default is True.
:param _preload_content: if False, the ApiResponse.data will
be set to none and raw_data will store the
HTTP response body without reading/decoding.
Default is True.
:type _preload_content: bool, optional
:param _return_http_data_only: response data instead of ApiResponse
object with status code, headers, etc
:type _return_http_data_only: bool, optional
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import tornado.gen
{{/tornado}}

from {{packageName}}.configuration import Configuration
from {{packageName}}.api_response import ApiResponse
import {{modelPackage}}
from {{packageName}} import rest
from {{packageName}}.exceptions import ApiValueError, ApiException
Expand Down Expand Up @@ -229,49 +230,46 @@ class ApiClient(object):

self.last_response = response_data

return_data = response_data

if not _preload_content:
{{^tornado}}
return return_data
{{/tornado}}
{{#tornado}}
raise tornado.gen.Return(return_data)
{{/tornado}}

response_type = response_types_map.get(str(response_data.status), None)

if response_type == "bytearray":
response_data.data = response_data.data
else:
match = None
content_type = response_data.getheader('content-type')
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)

# deserialize response data
if response_type == "bytearray":
return_data = response_data.data
elif response_type:
return_data = self.deserialize(response_data, response_type)
else:
return_data = None
return_data = None # assuming derialization is not needed
# data needs deserialization or returns HTTP data (deserialized) only
if _preload_content or _return_http_data_only:
response_type = response_types_map.get(str(response_data.status), None)

if response_type == "bytearray":
response_data.data = response_data.data
else:
match = None
content_type = response_data.getheader('content-type')
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)

# deserialize response data
if response_type == "bytearray":
return_data = response_data.data
elif response_type:
return_data = self.deserialize(response_data, response_type)
else:
return_data = None

{{^tornado}}
if _return_http_data_only:
return (return_data)
return return_data
else:
return (return_data, response_data.status,
response_data.getheaders())
return ApiResponse(status_code = response_data.status,
data = return_data,
headers = response_data.getheaders(),
raw_data = response_data.data)
{{/tornado}}
{{#tornado}}
if _return_http_data_only:
raise tornado.gen.Return(return_data)
else:
raise tornado.gen.Return((return_data, response_data.status,
response_data.getheaders()))
raise tornado.gen.Return(ApiResponse(status_code = response_data.status,
data = return_data,
headers = response_data.getheaders(),
raw_data = response_data.data))
{{/tornado}}

def sanitize_for_serialization(self, obj):
Expand Down Expand Up @@ -380,8 +378,8 @@ class ApiClient(object):
body=None, post_params=None, files=None,
response_types_map=None, auth_settings=None,
async_req=None, _return_http_data_only=None,
collection_formats=None,_preload_content=True,
_request_timeout=None, _host=None, _request_auth=None):
collection_formats=None, _preload_content=True,
_request_timeout=None, _host=None, _request_auth=None):
"""Makes the HTTP request (synchronous) and returns deserialized data.

To make an async_req request, set the async_req parameter.
Expand All @@ -400,13 +398,14 @@ class ApiClient(object):
:param files dict: key -> filename, value -> filepath,
for `multipart/form-data`.
:param async_req bool: execute request asynchronously
:param _return_http_data_only: response data without head status code
and headers
:param _return_http_data_only: response data instead of ApiResponse
object with status code, headers, etc
:param _preload_content: if False, the ApiResponse.data will
be set to none and raw_data will store the
HTTP response body without reading/decoding.
Default is True.
:param collection_formats: dict of collection formats for path, query,
header, and post parameters.
:param _preload_content: if False, the urllib3.HTTPResponse object will
be returned without reading/decoding response
data. Default is True.
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""API response object."""

from __future__ import annotations
from typing import Any, Dict, Optional
from pydantic import Field, StrictInt, StrictStr

class ApiResponse:
"""
API response object
"""

status_code: Optional[StrictInt] = Field(None, description="HTTP status code")
headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers")
data: Optional[Any] = Field(None, description="Deserialized data given the data type")
raw_data: Optional[Any] = Field(None, description="Raw data (HTTP response body)")

def __init__(self,
status_code=None,
headers=None,
data=None,
raw_data=None):
self.status_code = status_code
self.headers = headers
self.data = data
self.raw_data = raw_data
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ openapi_client/api/header_api.py
openapi_client/api/path_api.py
openapi_client/api/query_api.py
openapi_client/api_client.py
openapi_client/api_response.py
openapi_client/configuration.py
openapi_client/exceptions.py
openapi_client/models/__init__.py
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from openapi_client.api.query_api import QueryApi

# import ApiClient
from openapi_client.api_response import ApiResponse
from openapi_client.api_client import ApiClient
from openapi_client.configuration import Configuration
from openapi_client.exceptions import OpenApiException
Expand Down
Loading

0 comments on commit 021d3a3

Please sign in to comment.