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

View File

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

View File

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

View File

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

View File

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

View File

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