From 6725b761e10dd8fcf34b231563e03acc9da939c0 Mon Sep 17 00:00:00 2001 From: vsc-m Date: Fri, 20 Sep 2024 15:57:13 +0100 Subject: [PATCH 1/4] CP-2395 Clean up configuration.py --- .../src/thousandeyes_sdk/core/api_client.py | 47 +--- .../thousandeyes_sdk/core/configuration.py | 214 ------------------ 2 files changed, 2 insertions(+), 259 deletions(-) diff --git a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py index d8305ed4..0afc17a9 100644 --- a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py +++ b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py @@ -49,8 +49,6 @@ class ApiClient: :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 cookie: a cookie to include in the header when making calls - to the API """ PRIMITIVE_TYPES = (float, bool, bytes, str, int) @@ -71,19 +69,15 @@ class ApiClient: configuration=None, header_name=None, header_value=None, - cookie=None ) -> None: # use default configuration if none is provided if configuration is None: configuration = Configuration.get_default() self.configuration = 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 - self.client_side_validation = configuration.client_side_validation def __enter__(self): return self @@ -171,8 +165,6 @@ class ApiClient: # header parameters header_params = header_params or {} header_params.update(self.default_headers) - if self.cookie: - header_params['Cookie'] = self.cookie if header_params: header_params = self.sanitize_for_serialization(header_params) header_params = dict( @@ -190,7 +182,7 @@ class ApiClient: # specified safe chars, encode everything resource_path = resource_path.replace( '{%s}' % k, - quote(str(v), safe=config.safe_chars_for_path_param) + quote(str(v), safe='' ) # post parameters @@ -299,8 +291,6 @@ class ApiClient: try: if response_type == "bytearray": return_data = response_data.data - elif response_type == "file": - return_data = self.__deserialize_file(response_data) elif response_type is not None: match = None content_type = response_data.getheader('content-type') @@ -635,9 +625,7 @@ class ApiClient: The object type is the return value of sanitize_for_serialization(). :param auth_setting: auth settings for the endpoint """ - if auth_setting['in'] == 'cookie': - headers['Cookie'] = auth_setting['value'] - elif auth_setting['in'] == 'header': + if auth_setting['in'] == 'header': if auth_setting['type'] != 'http-signature': headers[auth_setting['key']] = auth_setting['value'] elif auth_setting['in'] == 'query': @@ -647,37 +635,6 @@ class ApiClient: 'Authentication token must be in `query` or `header`' ) - 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. - - handle file downloading - save response body into a tmp file and return the instance - - :param response: RESTResponse. - :return: file path. - """ - fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path) - os.close(fd) - os.remove(path) - - content_disposition = response.getheader("Content-Disposition") - if content_disposition: - m = re.search( - r'filename=[\'"]?([^\'"\s]+)[\'"]?', - content_disposition - ) - assert m is not None, "Unexpected 'content-disposition' header value" - filename = m.group(1) - path = os.path.join(os.path.dirname(path), filename) - - with open(path, "wb") as f: - f.write(response.data) - - return path - def __deserialize_primitive(self, data, klass): """Deserializes string to primitive type. diff --git a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py index e8445bdc..96aff8fa 100644 --- a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py +++ b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py @@ -26,51 +26,13 @@ import urllib3 from thousandeyes_sdk.core.thousandeyes_retry import ThousandEyesRetry -JSON_SCHEMA_VALIDATION_KEYWORDS = { - 'multipleOf', 'maximum', 'exclusiveMaximum', - 'minimum', 'exclusiveMinimum', 'maxLength', - 'minLength', 'pattern', 'maxItems', 'minItems' -} - class Configuration: - """This class contains various settings of the API client. - - :param host: Base url. - :param api_key: Dict to store API key(s). - Each entry in the dict specifies an API key. - The dict key is the name of the security scheme in the OAS specification. - The dict value is the API key secret. - :param api_key_prefix: Dict to store API prefix (e.g. Bearer). - The dict key is the name of the security scheme in the OAS specification. - The dict value is an API key prefix when generating the auth data. - :param username: Username for HTTP basic authentication. - :param password: Password for HTTP basic authentication. - :param access_token: Access token. - :param server_index: Index to servers configuration. - :param server_variables: Mapping with string values to replace variables in - templated server configuration. The validation of enums is performed for - variables with defined enum values before. - :param server_operation_index: Mapping from operation ID to an index to server - configuration. - :param server_operation_variables: Mapping from operation ID to a mapping with - string values to replace variables in templated server configuration. - The validation of enums is performed for variables with defined enum - values before. - :param ssl_ca_cert: str - the path to a file of concatenated CA certificates - in PEM format. - - :Example: - """ _default = None def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, ssl_ca_cert=None, retries=None ) -> None: @@ -79,37 +41,6 @@ class Configuration: self._base_path = "https://api.thousandeyes.com" if host is None else host """Default Base url """ - self.server_index = 0 if server_index is None and host is None else server_index - self.server_operation_index = server_operation_index or {} - """Default server index - """ - self.server_variables = server_variables or {} - self.server_operation_variables = server_operation_variables or {} - """Default server variables - """ - self.temp_folder_path = None - """Temp file folder for downloading files - """ - # Authentication Settings - self.api_key = {} - if api_key: - self.api_key = api_key - """dict to store API key(s) - """ - self.api_key_prefix = {} - if api_key_prefix: - self.api_key_prefix = api_key_prefix - """dict to store API prefix (e.g. Bearer) - """ - self.refresh_api_key_hook = None - """function hook to refresh API key if expired - """ - self.username = username - """Username for HTTP basic authentication - """ - self.password = password - """Password for HTTP basic authentication - """ self.access_token = access_token """Access token """ @@ -130,10 +61,6 @@ class Configuration: self.logger_file = None """Debug file location """ - self.debug = False - """Debug switch - """ - self.verify_ssl = True """SSL/TLS verification Set this to false to skip verifying SSL certificate when calling API @@ -155,7 +82,6 @@ class Configuration: """SSL/TLS Server Name Indication (SNI) Set this to the SNI value expected by the server. """ - self.connection_pool_maxsize = multiprocessing.cpu_count() * 5 """urllib3 connection pool's maximum number of connections saved per pool. urllib3 uses 1 connection as default value, but this is @@ -163,32 +89,23 @@ class Configuration: requests to the same host, which is often the case here. cpu_count * 5 is used as default value to increase performance. """ - self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None """Proxy headers """ - self.safe_chars_for_path_param = '' - """Safe chars for path_param - """ self.retries = ThousandEyesRetry() if retries: self.retries = retries """Adding retries to override urllib3 default value 3 """ - # Enable client side validation - self.client_side_validation = True - self.socket_options = None """Options to pass down to the underlying urllib3 socket """ - self.datetime_format = "%Y-%m-%dT%H:%M:%S.%f%z" """datetime format """ - self.date_format = "%Y-%m-%d" """date format """ @@ -204,7 +121,6 @@ class Configuration: result.logger = copy.copy(self.logger) # use setters to configure loggers result.logger_file = self.logger_file - result.debug = self.debug return result def __setattr__(self, name, value): @@ -221,16 +137,6 @@ class Configuration: """ cls._default = default - @classmethod - def get_default_copy(cls): - """Deprecated. Please use `get_default` instead. - - Deprecated. Please use `get_default` instead. - - :return: The configuration object. - """ - return cls.get_default() - @classmethod def get_default(cls): """Return the default configuration. @@ -276,37 +182,6 @@ class Configuration: for _, logger in self.logger.items(): logger.addHandler(self.logger_file_handler) - @property - def debug(self): - """Debug status - - :param value: The debug status, True or False. - :type: bool - """ - return self.__debug - - @debug.setter - def debug(self, value): - """Debug status - - :param value: The debug status, True or False. - :type: bool - """ - self.__debug = value - if self.__debug: - # if debug status is True, turn on debug logging - for _, logger in self.logger.items(): - 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 self.logger.items(): - logger.setLevel(logging.WARNING) - # turn off httplib debug - httplib.HTTPConnection.debuglevel = 0 - @property def logger_format(self): """The logger format. @@ -330,38 +205,6 @@ class Configuration: self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): - """Gets API key (with prefix if set). - - :param identifier: The identifier of apiKey. - :param alias: The alternative identifier of apiKey. - :return: The token for api key authentication. - """ - if self.refresh_api_key_hook is not None: - self.refresh_api_key_hook(self) - key = self.api_key.get(identifier, self.api_key.get(alias) if alias is not None else None) - if key: - prefix = self.api_key_prefix.get(identifier) - if prefix: - return "%s %s" % (prefix, key) - else: - return key - - def get_basic_auth_token(self): - """Gets HTTP basic authentication header (string). - - :return: The token for basic HTTP authentication. - """ - username = "" - if self.username is not None: - username = self.username - password = "" - if self.password is not None: - password = self.password - return urllib3.util.make_headers( - basic_auth=username + ':' + password - ).get('authorization') - def auth_settings(self): """Gets Auth Settings dict for api client. @@ -377,18 +220,6 @@ class Configuration: } return auth - def to_debug_report(self): - """Gets the essential information for debugging. - - :return: The report for debugging. - """ - return "Python SDK Debug Report:\n" \ - "OS: {env}\n" \ - "Python Version: {pyversion}\n" \ - "Version of the API: 7.0.0\n" \ - "SDK Package Version: 1.0.0". \ - format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): """Gets an array of host settings @@ -401,52 +232,7 @@ class Configuration: } ] - def get_host_from_settings(self, index, variables=None, servers=None): - """Gets host URL based on the index and variables - :param index: array index of the host settings - :param variables: hash of variable and the corresponding value - :param servers: an array of host settings or None - :return: URL based on host settings - """ - if index is None: - return self._base_path - - variables = {} if variables is None else variables - servers = self.get_host_settings() if servers is None else servers - - try: - server = servers[index] - except IndexError: - raise ValueError( - "Invalid index {0} when selecting the host settings. " - "Must be less than {1}".format(index, len(servers))) - - url = server['url'] - - # go through variables and replace placeholders - for variable_name, variable in server.get('variables', {}).items(): - used_value = variables.get( - variable_name, variable['default_value']) - - if 'enum_values' in variable \ - and used_value not in variable['enum_values']: - raise ValueError( - "The variable `{0}` in the host URL has invalid value " - "{1}. Must be {2}.".format( - variable_name, variables[variable_name], - variable['enum_values'])) - - url = url.replace("{" + variable_name + "}", used_value) - - return url - - @property - def host(self): - """Return generated host.""" - return self.get_host_from_settings(self.server_index, variables=self.server_variables) - @host.setter def host(self, value): """Fix base path.""" self._base_path = value - self.server_index = None From b2f6050ed6bd58122a71b1a6bf0de4c2fec0d513 Mon Sep 17 00:00:00 2001 From: vsc-m Date: Fri, 20 Sep 2024 16:27:07 +0100 Subject: [PATCH 2/4] CP-2395 Fix build --- .../src/thousandeyes_sdk/core/api_client.py | 2 +- .../src/thousandeyes_sdk/core/configuration.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py index 0afc17a9..6e640896 100644 --- a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py +++ b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py @@ -182,7 +182,7 @@ class ApiClient: # specified safe chars, encode everything resource_path = resource_path.replace( '{%s}' % k, - quote(str(v), safe='' + quote(str(v), safe='') ) # post parameters diff --git a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py index 96aff8fa..637b9b81 100644 --- a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py +++ b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py @@ -232,6 +232,11 @@ class Configuration: } ] + @property + def host(self): + """Return generated host.""" + return self.get_host_from_settings(self.server_index, variables={}) + @host.setter def host(self, value): """Fix base path.""" From d1d32568a0482d120a33f67c863619adca10ed85 Mon Sep 17 00:00:00 2001 From: vsc-m Date: Thu, 26 Sep 2024 13:41:50 +0100 Subject: [PATCH 3/4] CP-2395 More removals --- .../src/thousandeyes_sdk/core/api_client.py | 6 ------ .../src/thousandeyes_sdk/core/configuration.py | 14 +------------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py index 6e640896..3c65d8dd 100644 --- a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py +++ b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py @@ -178,12 +178,6 @@ class ApiClient: path_params, collection_formats ) - for k, v in path_params: - # specified safe chars, encode everything - resource_path = resource_path.replace( - '{%s}' % k, - quote(str(v), safe='') - ) # post parameters if post_params or files: diff --git a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py index 637b9b81..2a610fba 100644 --- a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py +++ b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/configuration.py @@ -220,22 +220,10 @@ class Configuration: } return auth - def get_host_settings(self): - """Gets an array of host settings - - :return: An array of host settings - """ - return [ - { - 'url': "https://api.thousandeyes.com", - 'description': "ThousandEyes API production URL", - } - ] - @property def host(self): """Return generated host.""" - return self.get_host_from_settings(self.server_index, variables={}) + return self._base_path @host.setter def host(self, value): From a4c6de92026ff38342e61bf8654c51cb2396a172 Mon Sep 17 00:00:00 2001 From: vsc-m Date: Thu, 26 Sep 2024 14:01:32 +0100 Subject: [PATCH 4/4] CP-2395 Undo removal of url encoding logic --- .../src/thousandeyes_sdk/core/api_client.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py index 3c65d8dd..6e640896 100644 --- a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py +++ b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/api_client.py @@ -178,6 +178,12 @@ class ApiClient: path_params, collection_formats ) + for k, v in path_params: + # specified safe chars, encode everything + resource_path = resource_path.replace( + '{%s}' % k, + quote(str(v), safe='') + ) # post parameters if post_params or files: