[python-client] Thread pool fix (#6396)

* [python-client] Added close() and join() for threadpool at ApiClient destructor.

* Updated stuff for CI
This commit is contained in:
Darshana Sanjeewan Adikari 2017-09-01 12:18:03 +02:00 committed by wing328
parent 0f1a61d9c2
commit a28ce0b604
10 changed files with 61 additions and 59 deletions

View File

@ -66,6 +66,10 @@ class ApiClient(object):
self.cookie = cookie
# Set default User-Agent.
self.user_agent = '{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{packageVersion}}}/python{{/httpUserAgent}}'
def __del__(self):
self.pool.close()
self.pool.join()
@property
def user_agent(self):

View File

@ -1 +1 @@
2.2.3-SNAPSHOT
2.3.0-SNAPSHOT

View File

@ -1,4 +1,4 @@
# petstore_api
# petstore-api
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ */ ' \" =end --
This Python package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project:

View File

@ -16,7 +16,7 @@ import re
import json
import mimetypes
import tempfile
import threading
from multiprocessing.pool import ThreadPool
from datetime import date, datetime
@ -64,6 +64,7 @@ class ApiClient(object):
configuration = Configuration()
self.configuration = configuration
self.pool = ThreadPool()
self.rest_client = RESTClientObject(configuration)
self.default_headers = {}
if header_name is not None:
@ -71,6 +72,10 @@ class ApiClient(object):
self.cookie = cookie
# Set default User-Agent.
self.user_agent = 'Swagger-Codegen/1.0.0/python'
def __del__(self):
self.pool.close()
self.pool.join()
@property
def user_agent(self):
@ -92,11 +97,11 @@ class ApiClient(object):
def __call_api(self, resource_path, method,
path_params=None, query_params=None, header_params=None,
body=None, post_params=None, files=None,
response_type=None, auth_settings=None, callback=None,
response_type=None, auth_settings=None,
_return_http_data_only=None, collection_formats=None, _preload_content=True,
_request_timeout=None):
config = Configuration()
config = self.configuration
# header parameters
header_params = header_params or {}
@ -159,12 +164,7 @@ class ApiClient(object):
else:
return_data = None
if callback:
if _return_http_data_only:
callback(return_data)
else:
callback((return_data, response_data.status, response_data.getheaders()))
elif _return_http_data_only:
if _return_http_data_only:
return (return_data)
else:
return (return_data, response_data.status, response_data.getheaders())
@ -278,7 +278,7 @@ class ApiClient(object):
def call_api(self, resource_path, method,
path_params=None, query_params=None, header_params=None,
body=None, post_params=None, files=None,
response_type=None, auth_settings=None, callback=None,
response_type=None, auth_settings=None, async=None,
_return_http_data_only=None, collection_formats=None, _preload_content=True,
_request_timeout=None):
"""
@ -298,9 +298,7 @@ class ApiClient(object):
:param response: Response data type.
:param files dict: key -> filename, value -> filepath,
for `multipart/form-data`.
:param callback function: Callback function for asynchronous request.
If provide this parameter,
the request will be called asynchronously.
:param async bool: execute request asynchronously
:param _return_http_data_only: response data without head status code and headers
:param collection_formats: dict of collection formats for path, query,
header, and post parameters.
@ -315,22 +313,20 @@ class ApiClient(object):
If parameter callback is None,
then the method will return the response directly.
"""
if callback is None:
if not async:
return self.__call_api(resource_path, method,
path_params, query_params, header_params,
body, post_params, files,
response_type, auth_settings, callback,
response_type, auth_settings,
_return_http_data_only, collection_formats, _preload_content, _request_timeout)
else:
thread = threading.Thread(target=self.__call_api,
args=(resource_path, method,
path_params, query_params,
header_params, body,
post_params, files,
response_type, auth_settings,
callback, _return_http_data_only,
collection_formats, _preload_content, _request_timeout))
thread.start()
thread = self.pool.apply_async(self.__call_api, (resource_path, method,
path_params, query_params,
header_params, body,
post_params, files,
response_type, auth_settings,
_return_http_data_only,
collection_formats, _preload_content, _request_timeout))
return thread
def request(self, method, url, query_params=None, headers=None,
@ -610,17 +606,23 @@ class ApiClient(object):
:param klass: class literal.
:return: model object.
"""
if not klass.swagger_types:
if not klass.swagger_types and not hasattr(klass, 'get_real_child_model'):
return data
kwargs = {}
for attr, attr_type in iteritems(klass.swagger_types):
if data is not None \
and klass.attribute_map[attr] in data \
and isinstance(data, (list, dict)):
value = data[klass.attribute_map[attr]]
kwargs[attr] = self.__deserialize(value, attr_type)
if klass.swagger_types is not None:
for attr, attr_type in iteritems(klass.swagger_types):
if data is not None \
and klass.attribute_map[attr] in data \
and isinstance(data, (list, dict)):
value = data[klass.attribute_map[attr]]
kwargs[attr] = self.__deserialize(value, attr_type)
instance = klass(**kwargs)
instance = klass(**kwargs)
if hasattr(instance, 'get_real_child_model'):
klass_name = instance.get_real_child_model(data)
if klass_name:
instance = self.__deserialize(data, klass_name)
return instance

View File

@ -39,22 +39,18 @@ class FakeApi(object):
"""
To test code injection */ ' \" =end -- \\r\\n \\n \\r
This method makes a synchronous HTTP request by default. To make an
asynchronous HTTP request, please define a `callback` function
to be invoked when receiving the response.
>>> def callback_function(response):
>>> pprint(response)
>>>
>>> thread = api.test_code_inject____end__rn_n_r(callback=callback_function)
asynchronous HTTP request, please pass async=True
>>> thread = api.test_code_inject____end__rn_n_r(async=True)
>>> result = thread.get()
:param callback function: The callback function
for asynchronous request. (optional)
:param async bool
:param str test_code_inject____end____rn_n_r: To test code injection */ ' \" =end -- \\r\\n \\n \\r
:return: None
If the method is called asynchronously,
returns the request thread.
"""
kwargs['_return_http_data_only'] = True
if kwargs.get('callback'):
if kwargs.get('async'):
return self.test_code_inject____end__rn_n_r_with_http_info(**kwargs)
else:
(data) = self.test_code_inject____end__rn_n_r_with_http_info(**kwargs)
@ -64,15 +60,11 @@ class FakeApi(object):
"""
To test code injection */ ' \" =end -- \\r\\n \\n \\r
This method makes a synchronous HTTP request by default. To make an
asynchronous HTTP request, please define a `callback` function
to be invoked when receiving the response.
>>> def callback_function(response):
>>> pprint(response)
>>>
>>> thread = api.test_code_inject____end__rn_n_r_with_http_info(callback=callback_function)
asynchronous HTTP request, please pass async=True
>>> thread = api.test_code_inject____end__rn_n_r_with_http_info(async=True)
>>> result = thread.get()
:param callback function: The callback function
for asynchronous request. (optional)
:param async bool
:param str test_code_inject____end____rn_n_r: To test code injection */ ' \" =end -- \\r\\n \\n \\r
:return: None
If the method is called asynchronously,
@ -80,7 +72,7 @@ class FakeApi(object):
"""
all_params = ['test_code_inject____end____rn_n_r']
all_params.append('callback')
all_params.append('async')
all_params.append('_return_http_data_only')
all_params.append('_preload_content')
all_params.append('_request_timeout')
@ -130,7 +122,7 @@ class FakeApi(object):
files=local_var_files,
response_type=None,
auth_settings=auth_settings,
callback=params.get('callback'),
async=params.get('async'),
_return_http_data_only=params.get('_return_http_data_only'),
_preload_content=params.get('_preload_content', True),
_request_timeout=params.get('_request_timeout'),

View File

@ -44,6 +44,7 @@ class ModelReturn(object):
"""
self.__return = None
self.discriminator = None
if _return is not None:
self._return = _return

View File

@ -61,8 +61,7 @@ class RESTClientObject(object):
# https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75
# https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680
# maxsize is the number of requests to host that are allowed in parallel
# ca_certs vs cert_file vs key_file
# http://stackoverflow.com/a/23957365/2985775
# Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html
# cert_reqs
if configuration.verify_ssl:
@ -142,7 +141,7 @@ class RESTClientObject(object):
url += '?' + urlencode(query_params)
if re.search('json', headers['Content-Type'], re.IGNORECASE):
request_body = None
if body:
if body is not None:
request_body = json.dumps(body)
r = self.pool_manager.request(method, url,
body=request_body,
@ -203,7 +202,7 @@ class RESTClientObject(object):
# log response body
logger.debug("response body: %s", r.data)
if r.status not in range(200, 206):
if not 200 <= r.status <= 299:
raise ApiException(http_resp=r)
return r

View File

@ -14,7 +14,7 @@
import sys
from setuptools import setup, find_packages
NAME = "petstore_api"
NAME = "petstore-api"
VERSION = "1.0.0"
# To install the library, run the following
#

View File

@ -94,7 +94,7 @@ This endpoint does not need any parameter.
### Return type
[**dict(str, int)**](dict.md)
**dict(str, int)**
### Authorization

View File

@ -72,6 +72,10 @@ class ApiClient(object):
self.cookie = cookie
# Set default User-Agent.
self.user_agent = 'Swagger-Codegen/1.0.0/python'
def __del__(self):
self.pool.close()
self.pool.join()
@property
def user_agent(self):