From 62444a7aaf480d0fc12c048ce7c86f8978a16a89 Mon Sep 17 00:00:00 2001 From: Gabriele Bonetti Date: Mon, 13 Nov 2017 05:50:10 +0100 Subject: [PATCH] Binary mode for file deserialization in python (#6936) * use wb mode in file deserialization * add auto generated files from security/python-petstore.sh --- .../main/resources/python/api_client.mustache | 2 +- .../python/docs/FakeApi.md | 4 +- .../python/petstore_api/__init__.py | 16 +- .../python/petstore_api/api/__init__.py | 6 + .../python/petstore_api/api/fake_api.py | 127 +++++++++++ .../python/petstore_api/api_client.py | 215 +++++++++--------- .../python/petstore_api/configuration.py | 91 ++++---- .../python/petstore_api/models/__init__.py | 5 +- .../petstore_api/models/model_return.py | 62 ++--- .../python/petstore_api/rest.py | 152 +++++++------ .../petstore-security-test/python/setup.py | 7 +- .../python-asyncio/petstore_api/api_client.py | 2 +- .../python-tornado/petstore_api/api_client.py | 2 +- .../python/petstore_api/api_client.py | 2 +- 14 files changed, 411 insertions(+), 282 deletions(-) create mode 100644 samples/client/petstore-security-test/python/petstore_api/api/__init__.py create mode 100644 samples/client/petstore-security-test/python/petstore_api/api/fake_api.py diff --git a/modules/swagger-codegen/src/main/resources/python/api_client.mustache b/modules/swagger-codegen/src/main/resources/python/api_client.mustache index c10eaa62af..6a9a1c2744 100644 --- a/modules/swagger-codegen/src/main/resources/python/api_client.mustache +++ b/modules/swagger-codegen/src/main/resources/python/api_client.mustache @@ -531,7 +531,7 @@ class ApiClient(object): content_disposition).group(1) path = os.path.join(os.path.dirname(path), filename) - with open(path, "w") as f: + with open(path, "wb") as f: f.write(response.data) return path diff --git a/samples/client/petstore-security-test/python/docs/FakeApi.md b/samples/client/petstore-security-test/python/docs/FakeApi.md index e35d744ef3..ba03f0fad1 100644 --- a/samples/client/petstore-security-test/python/docs/FakeApi.md +++ b/samples/client/petstore-security-test/python/docs/FakeApi.md @@ -12,7 +12,7 @@ Method | HTTP request | Description To test code injection */ ' \" =end -- \\r\\n \\n \\r -### Example +### Example ```python from __future__ import print_function import time @@ -24,7 +24,7 @@ from pprint import pprint api_instance = petstore_api.FakeApi() test_code_inject____end____rn_n_r = 'test_code_inject____end____rn_n_r_example' # str | To test code injection */ ' \" =end -- \\r\\n \\n \\r (optional) -try: +try: # To test code injection */ ' \" =end -- \\r\\n \\n \\r api_instance.test_code_inject____end__rn_n_r(test_code_inject____end____rn_n_r=test_code_inject____end____rn_n_r) except ApiException as e: diff --git a/samples/client/petstore-security-test/python/petstore_api/__init__.py b/samples/client/petstore-security-test/python/petstore_api/__init__.py index 0573fa17d0..af5957b1a0 100644 --- a/samples/client/petstore-security-test/python/petstore_api/__init__.py +++ b/samples/client/petstore-security-test/python/petstore_api/__init__.py @@ -1,9 +1,11 @@ # coding: utf-8 +# flake8: noqa + """ Swagger Petstore */ ' \" =end -- \\r\\n \\n \\r - 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 -- # noqa: E501 OpenAPI spec version: 1.0.0 */ ' \" =end -- \\r\\n \\n \\r Contact: apiteam@swagger.io */ ' \" =end -- \\r\\n \\n \\r @@ -13,13 +15,11 @@ from __future__ import absolute_import -# import models into sdk package -from .models.model_return import ModelReturn - # import apis into sdk package -from .apis.fake_api import FakeApi +from petstore_api.api.fake_api import FakeApi # import ApiClient -from .api_client import ApiClient - -from .configuration import Configuration +from petstore_api.api_client import ApiClient +from petstore_api.configuration import Configuration +# import models into sdk package +from petstore_api.models.model_return import ModelReturn diff --git a/samples/client/petstore-security-test/python/petstore_api/api/__init__.py b/samples/client/petstore-security-test/python/petstore_api/api/__init__.py new file mode 100644 index 0000000000..a2a6f73f45 --- /dev/null +++ b/samples/client/petstore-security-test/python/petstore_api/api/__init__.py @@ -0,0 +1,6 @@ +from __future__ import absolute_import + +# flake8: noqa + +# import apis into api package +from petstore_api.api.fake_api import FakeApi diff --git a/samples/client/petstore-security-test/python/petstore_api/api/fake_api.py b/samples/client/petstore-security-test/python/petstore_api/api/fake_api.py new file mode 100644 index 0000000000..0972042d7b --- /dev/null +++ b/samples/client/petstore-security-test/python/petstore_api/api/fake_api.py @@ -0,0 +1,127 @@ +# coding: utf-8 + +""" + Swagger Petstore */ ' \" =end -- \\r\\n \\n \\r + + 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 -- # noqa: E501 + + OpenAPI spec version: 1.0.0 */ ' \" =end -- \\r\\n \\n \\r + Contact: apiteam@swagger.io */ ' \" =end -- \\r\\n \\n \\r + Generated by: https://github.com/swagger-api/swagger-codegen.git +""" + + +from __future__ import absolute_import + +import re # noqa: F401 + +# python 2 and python 3 compatibility library +import six + +from petstore_api.api_client import ApiClient + + +class FakeApi(object): + """NOTE: This class is auto generated by the swagger code generator program. + + Do not edit the class manually. + Ref: https://github.com/swagger-api/swagger-codegen + """ + + def __init__(self, api_client=None): + if api_client is None: + api_client = ApiClient() + self.api_client = api_client + + def test_code_inject____end__rn_n_r(self, **kwargs): # noqa: E501 + """To test code injection */ ' \" =end -- \\r\\n \\n \\r # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.test_code_inject____end__rn_n_r(async=True) + >>> result = thread.get() + + :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('async'): + return self.test_code_inject____end__rn_n_r_with_http_info(**kwargs) # noqa: E501 + else: + (data) = self.test_code_inject____end__rn_n_r_with_http_info(**kwargs) # noqa: E501 + return data + + def test_code_inject____end__rn_n_r_with_http_info(self, **kwargs): # noqa: E501 + """To test code injection */ ' \" =end -- \\r\\n \\n \\r # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + 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 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. + """ + + all_params = ['test_code_inject____end____rn_n_r'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method test_code_inject____end__rn_n_r" % key + ) + params[key] = val + del params['kwargs'] + + collection_formats = {} + + path_params = {} + + query_params = [] + + header_params = {} + + form_params = [] + local_var_files = {} + if 'test_code_inject____end____rn_n_r' in params: + form_params.append(('test code inject */ ' " =end -- \r\n \n \r', params['test_code_inject____end____rn_n_r'])) # noqa: E501 + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json', '*/ \" =end -- ']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json', '*/ \" =end -- ']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/fake', 'PUT', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type=None, # noqa: E501 + auth_settings=auth_settings, + 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'), + collection_formats=collection_formats) diff --git a/samples/client/petstore-security-test/python/petstore_api/api_client.py b/samples/client/petstore-security-test/python/petstore_api/api_client.py index ea9f0084ba..360016c256 100644 --- a/samples/client/petstore-security-test/python/petstore_api/api_client.py +++ b/samples/client/petstore-security-test/python/petstore_api/api_client.py @@ -2,7 +2,7 @@ """ Swagger Petstore */ ' \" =end -- \\r\\n \\n \\r - 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 -- # noqa: E501 OpenAPI spec version: 1.0.0 */ ' \" =end -- \\r\\n \\n \\r Contact: apiteam@swagger.io */ ' \" =end -- \\r\\n \\n \\r @@ -11,27 +11,25 @@ from __future__ import absolute_import -import os -import re +import datetime import json import mimetypes -import tempfile from multiprocessing.pool import ThreadPool - -from datetime import date, datetime +import os +import re +import tempfile # python 2 and python 3 compatibility library -from six import PY3, integer_types, iteritems, text_type +import six from six.moves.urllib.parse import quote -from . import models -from .configuration import Configuration -from .rest import ApiException, RESTClientObject +from petstore_api.configuration import Configuration +import petstore_api.models +from petstore_api import rest class ApiClient(object): - """ - Generic API client for Swagger client library builds. + """Generic API client for Swagger client library builds. Swagger generic API client. This client handles the client- server communication, and is invariant across implementations. Specifics of @@ -42,64 +40,63 @@ class ApiClient(object): Ref: https://github.com/swagger-api/swagger-codegen Do not edit the class manually. - :param host: The base path for the server to call. + :param configuration: .Configuration object for this client :param header_name: a header to pass when making calls to the API. - :param header_value: a header value to pass when making calls to the API. + :param header_value: a header value to pass when making calls to + the API. + :param cookie: a cookie to include in the header when making calls + to the API """ - PRIMITIVE_TYPES = (float, bool, bytes, text_type) + integer_types + PRIMITIVE_TYPES = (float, bool, bytes, six.text_type) + six.integer_types NATIVE_TYPES_MAPPING = { 'int': int, - 'long': int if PY3 else long, + 'long': int if six.PY3 else long, # noqa: F821 'float': float, 'str': str, 'bool': bool, - 'date': date, - 'datetime': datetime, + 'date': datetime.date, + 'datetime': datetime.datetime, 'object': object, } - def __init__(self, configuration=None, header_name=None, header_value=None, cookie=None): + def __init__(self, configuration=None, header_name=None, header_value=None, + cookie=None): if configuration is None: configuration = Configuration() self.configuration = configuration self.pool = ThreadPool() - self.rest_client = RESTClientObject(configuration) + self.rest_client = rest.RESTClientObject(configuration) self.default_headers = {} if header_name is not None: self.default_headers[header_name] = header_value 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): - """ - Gets user agent. - """ + """User agent for this API client""" return self.default_headers['User-Agent'] @user_agent.setter def user_agent(self, value): - """ - Sets user agent. - """ self.default_headers['User-Agent'] = value def set_default_header(self, header_name, header_value): self.default_headers[header_name] = header_value - 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, - _return_http_data_only=None, collection_formats=None, _preload_content=True, - _request_timeout=None): + 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, + _return_http_data_only=None, collection_formats=None, + _preload_content=True, _request_timeout=None): config = self.configuration @@ -121,7 +118,9 @@ class ApiClient(object): for k, v in path_params: # specified safe chars, encode everything resource_path = resource_path.replace( - '{%s}' % k, quote(str(v), safe=config.safe_chars_for_path_param)) + '{%s}' % k, + quote(str(v), safe=config.safe_chars_for_path_param) + ) # query parameters if query_params: @@ -147,12 +146,11 @@ class ApiClient(object): url = self.configuration.host + resource_path # perform request and return response - response_data = self.request(method, url, - query_params=query_params, - headers=header_params, - post_params=post_params, body=body, - _preload_content=_preload_content, - _request_timeout=_request_timeout) + response_data = self.request( + method, url, query_params=query_params, headers=header_params, + post_params=post_params, body=body, + _preload_content=_preload_content, + _request_timeout=_request_timeout) self.last_response = response_data @@ -167,11 +165,11 @@ class ApiClient(object): if _return_http_data_only: return (return_data) else: - return (return_data, response_data.status, response_data.getheaders()) + return (return_data, response_data.status, + response_data.getheaders()) def sanitize_for_serialization(self, obj): - """ - Builds a JSON POST object. + """Builds a JSON POST object. If obj is None, return None. If obj is str, int, long, float, bool, return directly. @@ -194,7 +192,7 @@ class ApiClient(object): elif isinstance(obj, tuple): return tuple(self.sanitize_for_serialization(sub_obj) for sub_obj in obj) - elif isinstance(obj, (datetime, date)): + elif isinstance(obj, (datetime.datetime, datetime.date)): return obj.isoformat() if isinstance(obj, dict): @@ -206,15 +204,14 @@ class ApiClient(object): # Convert attribute name to json key in # model definition for request. obj_dict = {obj.attribute_map[attr]: getattr(obj, attr) - for attr, _ in iteritems(obj.swagger_types) + for attr, _ in six.iteritems(obj.swagger_types) if getattr(obj, attr) is not None} return {key: self.sanitize_for_serialization(val) - for key, val in iteritems(obj_dict)} + for key, val in six.iteritems(obj_dict)} def deserialize(self, response, response_type): - """ - Deserializes response into an object. + """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for @@ -236,8 +233,7 @@ class ApiClient(object): return self.__deserialize(data, response_type) def __deserialize(self, data, klass): - """ - Deserializes dict, list, str into an object. + """Deserializes dict, list, str into an object. :param data: dict, list or str. :param klass: class literal, or string of class name. @@ -256,21 +252,21 @@ class ApiClient(object): if klass.startswith('dict('): sub_kls = re.match('dict\(([^,]*), (.*)\)', klass).group(2) return {k: self.__deserialize(v, sub_kls) - for k, v in iteritems(data)} + for k, v in six.iteritems(data)} # convert str to class if klass in self.NATIVE_TYPES_MAPPING: klass = self.NATIVE_TYPES_MAPPING[klass] else: - klass = getattr(models, klass) + klass = getattr(petstore_api.models, klass) if klass in self.PRIMITIVE_TYPES: return self.__deserialize_primitive(data, klass) elif klass == object: return self.__deserialize_object(data) - elif klass == date: + elif klass == datetime.date: return self.__deserialize_date(data) - elif klass == datetime: + elif klass == datetime.datetime: return self.__deserialize_datatime(data) else: return self.__deserialize_model(data, klass) @@ -279,10 +275,10 @@ class ApiClient(object): path_params=None, query_params=None, header_params=None, body=None, post_params=None, files=None, response_type=None, auth_settings=None, async=None, - _return_http_data_only=None, collection_formats=None, _preload_content=True, - _request_timeout=None): - """ - Makes the HTTP request (synchronous) and return the deserialized data. + _return_http_data_only=None, collection_formats=None, + _preload_content=True, _request_timeout=None): + """Makes the HTTP request (synchronous) and returns deserialized data. + To make an async request, set the async parameter. :param resource_path: Path to method endpoint. @@ -299,13 +295,17 @@ class ApiClient(object): :param files dict: key -> filename, value -> filepath, for `multipart/form-data`. :param async bool: execute request 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, 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 (connection, read) timeouts. + :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 + (connection, read) timeouts. :return: If async parameter is True, the request will be called asynchronously. @@ -318,22 +318,23 @@ class ApiClient(object): 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_http_data_only, collection_formats, + _preload_content, _request_timeout) else: - thread = self.pool.apply_async(self.__call_api, (resource_path, method, - path_params, query_params, + 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)) + collection_formats, + _preload_content, _request_timeout)) return thread def request(self, method, url, query_params=None, headers=None, - post_params=None, body=None, _preload_content=True, _request_timeout=None): - """ - Makes the HTTP request using RESTClient. - """ + post_params=None, body=None, _preload_content=True, + _request_timeout=None): + """Makes the HTTP request using RESTClient.""" if method == "GET": return self.rest_client.GET(url, query_params=query_params, @@ -392,8 +393,7 @@ class ApiClient(object): ) def parameters_to_tuples(self, params, collection_formats): - """ - Get parameters as list of tuples, formatting collections. + """Get parameters as list of tuples, formatting collections. :param params: Parameters as dict or list of two-tuples :param dict collection_formats: Parameter collection formats @@ -402,7 +402,7 @@ class ApiClient(object): new_params = [] if collection_formats is None: collection_formats = {} - for k, v in iteritems(params) if isinstance(params, dict) else params: + for k, v in six.iteritems(params) if isinstance(params, dict) else params: # noqa: E501 if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': @@ -423,8 +423,7 @@ class ApiClient(object): return new_params def prepare_post_parameters(self, post_params=None, files=None): - """ - Builds form parameters. + """Builds form parameters. :param post_params: Normal form parameters. :param files: File parameters. @@ -436,7 +435,7 @@ class ApiClient(object): params = post_params if files: - for k, v in iteritems(files): + for k, v in six.iteritems(files): if not v: continue file_names = v if type(v) is list else [v] @@ -444,15 +443,15 @@ class ApiClient(object): with open(n, 'rb') as f: filename = os.path.basename(f.name) filedata = f.read() - mimetype = mimetypes.\ - guess_type(filename)[0] or 'application/octet-stream' - params.append(tuple([k, tuple([filename, filedata, mimetype])])) + mimetype = (mimetypes.guess_type(filename)[0] or + 'application/octet-stream') + params.append( + tuple([k, tuple([filename, filedata, mimetype])])) return params def select_header_accept(self, accepts): - """ - Returns `Accept` based on an array of accepts provided. + """Returns `Accept` based on an array of accepts provided. :param accepts: List of headers. :return: Accept (e.g. application/json). @@ -468,8 +467,7 @@ class ApiClient(object): return ', '.join(accepts) def select_header_content_type(self, content_types): - """ - Returns `Content-Type` based on an array of content_types provided. + """Returns `Content-Type` based on an array of content_types provided. :param content_types: List of content-types. :return: Content-Type (e.g. application/json). @@ -485,8 +483,7 @@ class ApiClient(object): return content_types[0] def update_params_for_auth(self, headers, querys, auth_settings): - """ - Updates header and query params based on authentication setting. + """Updates header and query params based on authentication setting. :param headers: Header parameters dict to be updated. :param querys: Query parameters tuple list to be updated. @@ -510,7 +507,8 @@ class ApiClient(object): ) def __deserialize_file(self, response): - """ + """Deserializes body to file + Saves response body into a file in a temporary folder, using the filename from the `Content-Disposition` header if provided. @@ -523,19 +521,17 @@ class ApiClient(object): content_disposition = response.getheader("Content-Disposition") if content_disposition: - filename = re.\ - search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition).\ - group(1) + filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', + content_disposition).group(1) path = os.path.join(os.path.dirname(path), filename) - with open(path, "w") as f: + with open(path, "wb") as f: f.write(response.data) return path def __deserialize_primitive(self, data, klass): - """ - Deserializes string to primitive type. + """Deserializes string to primitive type. :param data: str. :param klass: class literal. @@ -545,21 +541,19 @@ class ApiClient(object): try: return klass(data) except UnicodeEncodeError: - return unicode(data) + return six.u(data) except TypeError: return data def __deserialize_object(self, value): - """ - Return a original value. + """Return a original value. :return: object. """ return value def __deserialize_date(self, string): - """ - Deserializes string to date. + """Deserializes string to date. :param string: str. :return: date. @@ -570,14 +564,13 @@ class ApiClient(object): except ImportError: return string except ValueError: - raise ApiException( + raise rest.ApiException( status=0, - reason="Failed to parse `{0}` into a date object".format(string) + reason="Failed to parse `{0}` as date object".format(string) ) def __deserialize_datatime(self, string): - """ - Deserializes string to datetime. + """Deserializes string to datetime. The string should be in iso8601 datetime format. @@ -590,32 +583,32 @@ class ApiClient(object): except ImportError: return string except ValueError: - raise ApiException( + raise rest.ApiException( status=0, reason=( - "Failed to parse `{0}` into a datetime object" + "Failed to parse `{0}` as datetime object" .format(string) ) ) def __deserialize_model(self, data, klass): - """ - Deserializes list or dict to model. + """Deserializes list or dict to model. :param data: dict, list. :param klass: class literal. :return: model object. """ - if not klass.swagger_types and not hasattr(klass, 'get_real_child_model'): + if not klass.swagger_types and not hasattr(klass, + 'get_real_child_model'): return data kwargs = {} 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)): + for attr, attr_type in six.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) diff --git a/samples/client/petstore-security-test/python/petstore_api/configuration.py b/samples/client/petstore-security-test/python/petstore_api/configuration.py index da9d119a09..c5a442ee57 100644 --- a/samples/client/petstore-security-test/python/petstore_api/configuration.py +++ b/samples/client/petstore-security-test/python/petstore_api/configuration.py @@ -3,7 +3,7 @@ """ Swagger Petstore */ ' \" =end -- \\r\\n \\n \\r - 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 -- # noqa: E501 OpenAPI spec version: 1.0.0 */ ' \" =end -- \\r\\n \\n \\r Contact: apiteam@swagger.io */ ' \" =end -- \\r\\n \\n \\r @@ -13,24 +13,23 @@ from __future__ import absolute_import -import urllib3 - import copy import logging import multiprocessing import sys +import urllib3 -from six import iteritems -from six import with_metaclass +import six from six.moves import http_client as httplib + class TypeWithDefault(type): def __init__(cls, name, bases, dct): super(TypeWithDefault, cls).__init__(name, bases, dct) cls._default = None def __call__(cls): - if cls._default == None: + if cls._default is None: cls._default = type.__call__(cls) return copy.copy(cls._default) @@ -38,17 +37,15 @@ class TypeWithDefault(type): cls._default = copy.copy(default) -class Configuration(with_metaclass(TypeWithDefault, object)): - """ - NOTE: This class is auto generated by the swagger code generator program. +class Configuration(six.with_metaclass(TypeWithDefault, object)): + """NOTE: This class is auto generated by the swagger code generator program. + Ref: https://github.com/swagger-api/swagger-codegen Do not edit the class manually. """ def __init__(self): - """ - Constructor - """ + """Constructor""" # Default Base url self.host = "https://petstore.swagger.io */ ' \" =end -- \\r\\n \\n \\r/v2 */ ' \" =end -- \\r\\n \\n \\r" # Temp file folder for downloading files @@ -83,7 +80,8 @@ class Configuration(with_metaclass(TypeWithDefault, object)): self.debug = False # SSL/TLS verification - # Set this to false to skip verifying SSL certificate when calling API from https server. + # Set this to false to skip verifying SSL certificate when calling API + # from https server. self.verify_ssl = True # Set this to customize the certificate file to verify the peer. self.ssl_ca_cert = None @@ -101,7 +99,6 @@ class Configuration(with_metaclass(TypeWithDefault, object)): # cpu_count * 5 is used as default value to increase performance. self.connection_pool_maxsize = multiprocessing.cpu_count() * 5 - # Proxy URL self.proxy = None # Safe chars for path_param @@ -109,18 +106,22 @@ class Configuration(with_metaclass(TypeWithDefault, object)): @property def logger_file(self): - """ - Gets the logger_file. + """The logger file. + + If the logger_file is None, then add stream handler and remove file + handler. Otherwise, add file handler and remove stream handler. + + :param value: The logger_file path. + :type: str """ return self.__logger_file @logger_file.setter def logger_file(self, value): - """ - Sets the logger_file. + """The logger file. - If the logger_file is None, then add stream handler and remove file handler. - Otherwise, add file handler and remove stream handler. + If the logger_file is None, then add stream handler and remove file + handler. Otherwise, add file handler and remove stream handler. :param value: The logger_file path. :type: str @@ -131,7 +132,7 @@ class Configuration(with_metaclass(TypeWithDefault, object)): # then add file handler and remove stream handler. self.logger_file_handler = logging.FileHandler(self.__logger_file) self.logger_file_handler.setFormatter(self.logger_formatter) - for _, logger in iteritems(self.logger): + for _, logger in six.iteritems(self.logger): logger.addHandler(self.logger_file_handler) if self.logger_stream_handler: logger.removeHandler(self.logger_stream_handler) @@ -140,22 +141,23 @@ class Configuration(with_metaclass(TypeWithDefault, object)): # then add stream handler and remove file handler. self.logger_stream_handler = logging.StreamHandler() self.logger_stream_handler.setFormatter(self.logger_formatter) - for _, logger in iteritems(self.logger): + for _, logger in six.iteritems(self.logger): logger.addHandler(self.logger_stream_handler) if self.logger_file_handler: logger.removeHandler(self.logger_file_handler) @property def debug(self): - """ - Gets the debug status. + """Debug status + + :param value: The debug status, True or False. + :type: bool """ return self.__debug @debug.setter def debug(self, value): - """ - Sets the debug status. + """Debug status :param value: The debug status, True or False. :type: bool @@ -163,29 +165,32 @@ class Configuration(with_metaclass(TypeWithDefault, object)): self.__debug = value if self.__debug: # if debug status is True, turn on debug logging - for _, logger in iteritems(self.logger): + for _, logger in six.iteritems(self.logger): logger.setLevel(logging.DEBUG) # turn on httplib debug httplib.HTTPConnection.debuglevel = 1 else: # if debug status is False, turn off debug logging, # setting log level to default `logging.WARNING` - for _, logger in iteritems(self.logger): + for _, logger in six.iteritems(self.logger): logger.setLevel(logging.WARNING) # turn off httplib debug httplib.HTTPConnection.debuglevel = 0 @property def logger_format(self): - """ - Gets the logger_format. + """The logger format. + + The logger_formatter will be updated when sets logger_format. + + :param value: The format string. + :type: str """ return self.__logger_format @logger_format.setter def logger_format(self, value): - """ - Sets the logger_format. + """The logger format. The logger_formatter will be updated when sets logger_format. @@ -196,29 +201,28 @@ class Configuration(with_metaclass(TypeWithDefault, object)): self.logger_formatter = logging.Formatter(self.__logger_format) def get_api_key_with_prefix(self, identifier): - """ - Gets API key (with prefix if set). + """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. :return: The token for api key authentication. """ - if self.api_key.get(identifier) and self.api_key_prefix.get(identifier): - return self.api_key_prefix[identifier] + ' ' + self.api_key[identifier] + if (self.api_key.get(identifier) and + self.api_key_prefix.get(identifier)): + return self.api_key_prefix[identifier] + ' ' + self.api_key[identifier] # noqa: E501 elif self.api_key.get(identifier): return self.api_key[identifier] def get_basic_auth_token(self): - """ - Gets HTTP basic authentication header (string). + """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. """ - return urllib3.util.make_headers(basic_auth=self.username + ':' + self.password)\ - .get('authorization') + return urllib3.util.make_headers( + basic_auth=self.username + ':' + self.password + ).get('authorization') def auth_settings(self): - """ - Gets Auth Settings dict for api client. + """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ @@ -242,8 +246,7 @@ class Configuration(with_metaclass(TypeWithDefault, object)): } def to_debug_report(self): - """ - Gets the essential information for debugging. + """Gets the essential information for debugging. :return: The report for debugging. """ diff --git a/samples/client/petstore-security-test/python/petstore_api/models/__init__.py b/samples/client/petstore-security-test/python/petstore_api/models/__init__.py index a75a00eb19..ff65654b12 100644 --- a/samples/client/petstore-security-test/python/petstore_api/models/__init__.py +++ b/samples/client/petstore-security-test/python/petstore_api/models/__init__.py @@ -1,9 +1,10 @@ # coding: utf-8 +# flake8: noqa """ Swagger Petstore */ ' \" =end -- \\r\\n \\n \\r - 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 -- # noqa: E501 OpenAPI spec version: 1.0.0 */ ' \" =end -- \\r\\n \\n \\r Contact: apiteam@swagger.io */ ' \" =end -- \\r\\n \\n \\r @@ -14,4 +15,4 @@ from __future__ import absolute_import # import models into model package -from .model_return import ModelReturn +from petstore_api.models.model_return import ModelReturn diff --git a/samples/client/petstore-security-test/python/petstore_api/models/model_return.py b/samples/client/petstore-security-test/python/petstore_api/models/model_return.py index bb6813619a..a4edf0658f 100644 --- a/samples/client/petstore-security-test/python/petstore_api/models/model_return.py +++ b/samples/client/petstore-security-test/python/petstore_api/models/model_return.py @@ -3,7 +3,7 @@ """ Swagger Petstore */ ' \" =end -- \\r\\n \\n \\r - 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 -- # noqa: E501 OpenAPI spec version: 1.0.0 */ ' \" =end -- \\r\\n \\n \\r Contact: apiteam@swagger.io */ ' \" =end -- \\r\\n \\n \\r @@ -11,18 +11,18 @@ """ -from pprint import pformat -from six import iteritems -import re +import pprint +import re # noqa: F401 + +import six class ModelReturn(object): - """ - NOTE: This class is auto generated by the swagger code generator program. + """NOTE: This class is auto generated by the swagger code generator program. + Do not edit the class manually. """ - """ Attributes: swagger_types (dict): The key is attribute name @@ -38,47 +38,43 @@ class ModelReturn(object): '_return': 'return' } - def __init__(self, _return=None): - """ - ModelReturn - a model defined in Swagger - """ + def __init__(self, _return=None): # noqa: E501 + """ModelReturn - a model defined in Swagger""" # noqa: E501 self.__return = None self.discriminator = None if _return is not None: - self._return = _return + self._return = _return @property def _return(self): - """ - Gets the _return of this ModelReturn. - property description */ ' \" =end -- \\r\\n \\n \\r + """Gets the _return of this ModelReturn. # noqa: E501 - :return: The _return of this ModelReturn. + property description */ ' \" =end -- \\r\\n \\n \\r # noqa: E501 + + :return: The _return of this ModelReturn. # noqa: E501 :rtype: int """ return self.__return @_return.setter def _return(self, _return): - """ - Sets the _return of this ModelReturn. - property description */ ' \" =end -- \\r\\n \\n \\r + """Sets the _return of this ModelReturn. - :param _return: The _return of this ModelReturn. + property description */ ' \" =end -- \\r\\n \\n \\r # noqa: E501 + + :param _return: The _return of this ModelReturn. # noqa: E501 :type: int """ self.__return = _return def to_dict(self): - """ - Returns the model properties as a dict - """ + """Returns the model properties as a dict""" result = {} - for attr, _ in iteritems(self.swagger_types): + for attr, _ in six.iteritems(self.swagger_types): value = getattr(self, attr) if isinstance(value, list): result[attr] = list(map( @@ -99,28 +95,20 @@ class ModelReturn(object): return result def to_str(self): - """ - Returns the string representation of the model - """ - return pformat(self.to_dict()) + """Returns the string representation of the model""" + return pprint.pformat(self.to_dict()) def __repr__(self): - """ - For `print` and `pprint` - """ + """For `print` and `pprint`""" return self.to_str() def __eq__(self, other): - """ - Returns true if both objects are equal - """ + """Returns true if both objects are equal""" if not isinstance(other, ModelReturn): return False return self.__dict__ == other.__dict__ def __ne__(self, other): - """ - Returns true if both objects are not equal - """ + """Returns true if both objects are not equal""" return not self == other diff --git a/samples/client/petstore-security-test/python/petstore_api/rest.py b/samples/client/petstore-security-test/python/petstore_api/rest.py index 8ccd6a6f5e..1f21e82870 100644 --- a/samples/client/petstore-security-test/python/petstore_api/rest.py +++ b/samples/client/petstore-security-test/python/petstore_api/rest.py @@ -3,7 +3,7 @@ """ Swagger Petstore */ ' \" =end -- \\r\\n \\n \\r - 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 -- # noqa: E501 OpenAPI spec version: 1.0.0 */ ' \" =end -- \\r\\n \\n \\r Contact: apiteam@swagger.io */ ' \" =end -- \\r\\n \\n \\r @@ -15,13 +15,13 @@ from __future__ import absolute_import import io import json -import ssl -import certifi import logging import re +import ssl +import certifi # python 2 and python 3 compatibility library -from six import PY3 +import six from six.moves.urllib.parse import urlencode try: @@ -42,15 +42,11 @@ class RESTResponse(io.IOBase): self.data = resp.data def getheaders(self): - """ - Returns a dictionary of the response headers. - """ + """Returns a dictionary of the response headers.""" return self.urllib3_response.getheaders() def getheader(self, name, default=None): - """ - Returns a given response header. - """ + """Returns a given response header.""" return self.urllib3_response.getheader(name, default) @@ -58,10 +54,10 @@ class RESTClientObject(object): def __init__(self, configuration, pools_size=4, maxsize=None): # urllib3.PoolManager will pass all kw parameters to connectionpool - # 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 - # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html + # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501 + # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501 + # maxsize is the number of requests to host that are allowed in parallel # noqa: E501 + # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501 # cert_reqs if configuration.verify_ssl: @@ -78,7 +74,7 @@ class RESTClientObject(object): addition_pool_args = {} if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = configuration.assert_hostname + addition_pool_args['assert_hostname'] = configuration.assert_hostname # noqa: E501 if maxsize is None: if configuration.connection_pool_maxsize is not None: @@ -110,8 +106,10 @@ class RESTClientObject(object): ) def request(self, method, url, query_params=None, headers=None, - body=None, post_params=None, _preload_content=True, _request_timeout=None): - """ + body=None, post_params=None, _preload_content=True, + _request_timeout=None): + """Perform requests. + :param method: http request method :param url: http request url :param query_params: query parameters in the url @@ -120,13 +118,17 @@ class RESTClientObject(object): :param post_params: request post parameters, `application/x-www-form-urlencoded` and `multipart/form-data` - :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 (connection, read) timeouts. + :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 + (connection, read) timeouts. """ method = method.upper() - assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', 'PATCH', 'OPTIONS'] + assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', + 'PATCH', 'OPTIONS'] if post_params and body: raise ValueError( @@ -138,10 +140,12 @@ class RESTClientObject(object): timeout = None if _request_timeout: - if isinstance(_request_timeout, (int, ) if PY3 else (int, long)): + if isinstance(_request_timeout, (int, ) if six.PY3 else (int, long)): # noqa: E501,F821 timeout = urllib3.Timeout(total=_request_timeout) - elif isinstance(_request_timeout, tuple) and len(_request_timeout) == 2: - timeout = urllib3.Timeout(connect=_request_timeout[0], read=_request_timeout[1]) + elif (isinstance(_request_timeout, tuple) and + len(_request_timeout) == 2): + timeout = urllib3.Timeout( + connect=_request_timeout[0], read=_request_timeout[1]) if 'Content-Type' not in headers: headers['Content-Type'] = 'application/json' @@ -155,42 +159,48 @@ class RESTClientObject(object): request_body = None if body is not None: request_body = json.dumps(body) - r = self.pool_manager.request(method, url, - body=request_body, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - elif headers['Content-Type'] == 'application/x-www-form-urlencoded': - r = self.pool_manager.request(method, url, - fields=post_params, - encode_multipart=False, - preload_content=_preload_content, - timeout=timeout, - headers=headers) + r = self.pool_manager.request( + method, url, + body=request_body, + preload_content=_preload_content, + timeout=timeout, + headers=headers) + elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 + r = self.pool_manager.request( + method, url, + fields=post_params, + encode_multipart=False, + preload_content=_preload_content, + timeout=timeout, + headers=headers) elif headers['Content-Type'] == 'multipart/form-data': - # must del headers['Content-Type'], or the correct Content-Type - # which generated by urllib3 will be overwritten. + # must del headers['Content-Type'], or the correct + # Content-Type which generated by urllib3 will be + # overwritten. del headers['Content-Type'] - r = self.pool_manager.request(method, url, - fields=post_params, - encode_multipart=True, - preload_content=_preload_content, - timeout=timeout, - headers=headers) + r = self.pool_manager.request( + method, url, + fields=post_params, + encode_multipart=True, + preload_content=_preload_content, + timeout=timeout, + headers=headers) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is provided - # in serialized form + # other content types than Json when `body` argument is + # provided in serialized form elif isinstance(body, str): request_body = body - r = self.pool_manager.request(method, url, - body=request_body, - preload_content=_preload_content, - timeout=timeout, - headers=headers) + r = self.pool_manager.request( + method, url, + body=request_body, + preload_content=_preload_content, + timeout=timeout, + headers=headers) else: # Cannot generate the request from given parameters - msg = """Cannot prepare a request message for provided arguments. - Please check that your arguments match declared content type.""" + msg = """Cannot prepare a request message for provided + arguments. Please check that your arguments match + declared content type.""" raise ApiException(status=0, reason=msg) # For `GET`, `HEAD` else: @@ -208,7 +218,7 @@ class RESTClientObject(object): # In the python 3, the response.data is bytes. # we need to decode it to string. - if PY3: + if six.PY3: r.data = r.data.decode('utf8') # log response body @@ -219,22 +229,24 @@ class RESTClientObject(object): return r - def GET(self, url, headers=None, query_params=None, _preload_content=True, _request_timeout=None): + def GET(self, url, headers=None, query_params=None, _preload_content=True, + _request_timeout=None): return self.request("GET", url, headers=headers, _preload_content=_preload_content, _request_timeout=_request_timeout, query_params=query_params) - def HEAD(self, url, headers=None, query_params=None, _preload_content=True, _request_timeout=None): + def HEAD(self, url, headers=None, query_params=None, _preload_content=True, + _request_timeout=None): return self.request("HEAD", url, headers=headers, _preload_content=_preload_content, _request_timeout=_request_timeout, query_params=query_params) - def OPTIONS(self, url, headers=None, query_params=None, post_params=None, body=None, _preload_content=True, - _request_timeout=None): + def OPTIONS(self, url, headers=None, query_params=None, post_params=None, + body=None, _preload_content=True, _request_timeout=None): return self.request("OPTIONS", url, headers=headers, query_params=query_params, @@ -243,7 +255,8 @@ class RESTClientObject(object): _request_timeout=_request_timeout, body=body) - def DELETE(self, url, headers=None, query_params=None, body=None, _preload_content=True, _request_timeout=None): + def DELETE(self, url, headers=None, query_params=None, body=None, + _preload_content=True, _request_timeout=None): return self.request("DELETE", url, headers=headers, query_params=query_params, @@ -251,8 +264,8 @@ class RESTClientObject(object): _request_timeout=_request_timeout, body=body) - def POST(self, url, headers=None, query_params=None, post_params=None, body=None, _preload_content=True, - _request_timeout=None): + def POST(self, url, headers=None, query_params=None, post_params=None, + body=None, _preload_content=True, _request_timeout=None): return self.request("POST", url, headers=headers, query_params=query_params, @@ -261,8 +274,8 @@ class RESTClientObject(object): _request_timeout=_request_timeout, body=body) - def PUT(self, url, headers=None, query_params=None, post_params=None, body=None, _preload_content=True, - _request_timeout=None): + def PUT(self, url, headers=None, query_params=None, post_params=None, + body=None, _preload_content=True, _request_timeout=None): return self.request("PUT", url, headers=headers, query_params=query_params, @@ -271,8 +284,8 @@ class RESTClientObject(object): _request_timeout=_request_timeout, body=body) - def PATCH(self, url, headers=None, query_params=None, post_params=None, body=None, _preload_content=True, - _request_timeout=None): + def PATCH(self, url, headers=None, query_params=None, post_params=None, + body=None, _preload_content=True, _request_timeout=None): return self.request("PATCH", url, headers=headers, query_params=query_params, @@ -297,13 +310,12 @@ class ApiException(Exception): self.headers = None def __str__(self): - """ - Custom error messages for exception - """ + """Custom error messages for exception""" error_message = "({0})\n"\ "Reason: {1}\n".format(self.status, self.reason) if self.headers: - error_message += "HTTP response headers: {0}\n".format(self.headers) + error_message += "HTTP response headers: {0}\n".format( + self.headers) if self.body: error_message += "HTTP response body: {0}\n".format(self.body) diff --git a/samples/client/petstore-security-test/python/setup.py b/samples/client/petstore-security-test/python/setup.py index d752ddcc05..50ee772851 100644 --- a/samples/client/petstore-security-test/python/setup.py +++ b/samples/client/petstore-security-test/python/setup.py @@ -3,7 +3,7 @@ """ Swagger Petstore */ ' \" =end -- \\r\\n \\n \\r - 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 -- # noqa: E501 OpenAPI spec version: 1.0.0 */ ' \" =end -- \\r\\n \\n \\r Contact: apiteam@swagger.io */ ' \" =end -- \\r\\n \\n \\r @@ -11,8 +11,7 @@ """ -import sys -from setuptools import setup, find_packages +from setuptools import setup, find_packages # noqa: H301 NAME = "petstore-api" VERSION = "1.0.0" @@ -36,6 +35,6 @@ setup( packages=find_packages(), include_package_data=True, long_description="""\ - 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 -- # noqa: E501 """ ) diff --git a/samples/client/petstore/python-asyncio/petstore_api/api_client.py b/samples/client/petstore/python-asyncio/petstore_api/api_client.py index c0222901b5..6029e8fa11 100644 --- a/samples/client/petstore/python-asyncio/petstore_api/api_client.py +++ b/samples/client/petstore/python-asyncio/petstore_api/api_client.py @@ -525,7 +525,7 @@ class ApiClient(object): content_disposition).group(1) path = os.path.join(os.path.dirname(path), filename) - with open(path, "w") as f: + with open(path, "wb") as f: f.write(response.data) return path diff --git a/samples/client/petstore/python-tornado/petstore_api/api_client.py b/samples/client/petstore/python-tornado/petstore_api/api_client.py index d705ec3f3f..222812fdb7 100644 --- a/samples/client/petstore/python-tornado/petstore_api/api_client.py +++ b/samples/client/petstore/python-tornado/petstore_api/api_client.py @@ -527,7 +527,7 @@ class ApiClient(object): content_disposition).group(1) path = os.path.join(os.path.dirname(path), filename) - with open(path, "w") as f: + with open(path, "wb") as f: f.write(response.data) return path diff --git a/samples/client/petstore/python/petstore_api/api_client.py b/samples/client/petstore/python/petstore_api/api_client.py index c507888bc3..ec4e3cd5c4 100644 --- a/samples/client/petstore/python/petstore_api/api_client.py +++ b/samples/client/petstore/python/petstore_api/api_client.py @@ -525,7 +525,7 @@ class ApiClient(object): content_disposition).group(1) path = os.path.join(os.path.dirname(path), filename) - with open(path, "w") as f: + with open(path, "wb") as f: f.write(response.data) return path