def class_to_dict(instance: Any, class_type: Type[T]) -> dict: ''' The method casts a classes attribute structure to a dict. :param instance: The input instance of a class. :type instance: Any :param class_type: The input class type. :type class_type: Type[T] :returns: A dictionary of the input classes attributes. :rtype: dict :raises Exception: If the class cannot be cast to a dict. ''' dict_of_class = None try: check_class(instance, class_type) dict_of_class = cast(Any, instance).to_dict() except: msg = messages.ERROR_COMMON_CLASS_TO_DICT.format( str(instance), str(class_type)) logger.error(msg) raise PAWException(msg) return dict_of_class
def from_json(query_registration_return_json: Any): """ Create an QueryRegistrationReturn object from json (dictonary or str). :param query_registration_return_json: A json dictionary that contains the keys of an QueryRegistrationReturn or a string representation of a json dictionary. :type query_registration_return_json: Any :rtype: ibmpairs.dashboard.QueryRegistrationReturn :raises Exception: if not a dictionary or a string. """ if isinstance(query_registration_return_json, dict): query_registration_return = QueryRegistrationReturn.from_dict( query_registration_return_json) elif isinstance(query_registration_return_json, str): query_registration_return_dict = json.loads( query_registration_return_json) query_registration_return = QueryRegistrationReturn.from_dict( query_registration_return_dict) else: msg = messages.ERROR_FROM_JSON_TYPE_NOT_RECOGNIZED.format( type(query_registration_return_json), "query_registration_return_json") logger.error(msg) raise common.PAWException(msg) return query_registration_return
def check_str(s: Any) -> str: ''' The method checks if the input value is of type str, if the input type is int a cast is attempted. :param s: The input value to check. :type s: str :returns: The input value. :rtype: str :raises Exception: If the type of 's' is not 'str' or 'int'. If the input value cannot be cast to 'str'. ''' string = None if isinstance(s, str): string = s elif isinstance(s, int): try: string = str(s) except: msg = messages.ERROR_COMMON_INT_TO_STR.format(s) logger.error(msg) raise PAWException(msg) else: msg = messages.ERROR_COMMON_CHECK_STR.format(type(s), str(s)) logger.error(msg) raise PAWException(msg) return string
def check_int(i: Any): ''' The method checks if the input value is of type int, if the input type is str a cast is attempted. :param s: The input value to check. :type s: int :returns: The input value. :rtype: int :raises Exception: If the type of 'i' is not 'int' or 'str'. If the input value cannot be cast to 'int'. ''' integer = None if isinstance(i, int): integer = i elif isinstance(i, str): try: integer = int(i) except: msg = messages.ERROR_COMMON_STR_TO_INT.format(i) logger.error(msg) raise PAWException(msg) else: msg = messages.ERROR_COMMON_CHECK_INT.format(type(i), str(i)) logger.error(msg) raise PAWException(msg) return integer
def set_client(input_client, global_client, self_client=None): """ The method selects a ibmpairs.client.Client from a few choices. :param input_client: A client input into the method that calls set_client(). :type input_client: ibmpairs.client.Client :param global_client: The global client in the environment. :type global_client: ibmpairs.client.Client :param self_client: The client held in the object that calls the method that calls set_client(). :type self_client: ibmpairs.client.Client :returns: the selected client from the hierarchy. :rtype: ibmpairs.client.Client :raises Exception: If no client is present. """ if input_client is not None: msg = messages.DEBUG_CLIENT_PROVIDED_FOUND logger.debug(msg) return input_client elif (input_client is None) and (self_client is not None): msg = messages.DEBUG_CLIENT_IN_OBJECT_FOUND logger.debug(msg) return self_client elif (input_client is None) and (self_client is None) and (global_client is not None): msg = messages.DEBUG_CLIENT_GLOBAL_FOUND logger.debug(msg) return global_client else: msg = messages.ERROR_NO_CLIENT logger.error(msg) raise PAWException(msg)
def session(self, authentication=None, headers=None, ssl=None, verify_ssl=True): """ A wrapper method around aiohttp.ClientSession. :param authentication: A username for the user. :type authentication: ibmpairs.authentication.Basic or ibmpairs.authentication.OAuth2 :param headers: A dictionary of request headers. :type headers: dict :param ssl: SSL. :type ssl: str :param verify_ssl: Verify SSL. :type verify_ssl: bool :returns: A aiohttp.ClientSession using the attributes provided. :rtype: aiohttp.ClientSession """ if headers is not None: self.set_headers(headers) msg = messages.DEBUG_CLIENT_SET_HEADERS.format(headers) logger.debug(msg) if authentication is not None: self.set_authentication(authentication) msg = messages.DEBUG_CLIENT_SET_HEADERS.format(authentication) logger.debug(msg) connector = aiohttp.TCPConnector(ssl=ssl, verify_ssl=verify_ssl) if self.authentication_mode(self._authentication) in ['Basic', 'None']: # If authentication.Basic then get set authenication tuple. if self.authentication_mode(self._authentication) in ['Basic']: authentication = aiohttp.BasicAuth( self._authentication.username, self._authentication.password) session = aiohttp.ClientSession(connector=connector, auth=authentication, headers=self._headers) elif self.authentication_mode(self._authentication) in ['OAuth2']: # Add bearer token to headers. token = 'Bearer ' + self._authentication.jwt_token self.append_header('Authorization', token) session = aiohttp.ClientSession(connector=connector, headers=self._headers) else: msg = messages.ERROR_CLIENT_AUTHENTICATION_MECHANISM.format( self.authentication_mode(self._authentication)) logger.error(msg) raise common.PAWException(msg) return session
def get(self, url, headers=None, verify=True): """ A wrapper method around requests.get. :param url: A URL to GET. :type url: str :param headers: A dictionary of request headers. :type headers: dict :param verify: Verify SSL. :type verify: bool :returns: A requests.Response object. :rtype: requests.Response """ response = None if headers is not None: self.set_headers(headers) msg = messages.DEBUG_CLIENT_SET_HEADERS.format('GET', headers) logger.debug(msg) if self.authentication_mode( self._authentication) in ['Basic', 'tuple', 'Dict', 'None']: # If Basic, construct an authentication tuple. if self.authentication_mode(self._authentication) in ['Basic']: authentication = self._authentication.get_credentials() response = requests.get(url, auth=authentication, headers=self._headers, verify=verify) elif self.authentication_mode(self._authentication) in ['OAuth2']: token = 'Bearer ' + self._authentication.jwt_token self.append_header('Authorization', token) response = requests.get(url, headers=self._headers, verify=verify) if response.status_code == 403: token_refresh_message = constants.CLIENT_TOKEN_REFRESH_MESSAGE if response.json() is not None: response_string = json.dumps(response.json()) if token_refresh_message in response_string: self._authentication.refresh_auth_token() token = 'Bearer ' + self._authentication.jwt_token self.append_header('Authorization', token) response = requests.get(url, headers=self._headers, verify=verify) else: msg = messages.ERROR_AUTHENTICATION_TYPE_NOT_RECOGNIZED.format( type(self._authentication)) logger.error(msg) raise Exception(msg) return response
def refresh_auth_token(self, verify = constants.GLOBAL_SSL_VERIFY ): """ The method submits a request to the authentication system for a refreshed token, gets a response and updates the internal self._oauth2_return and self._jwt_token objects. """ msg = messages.INFO_AUTHENTICATION_TOKEN_REFRESH logger.info(msg) response = None response_oauth2_return = None if (self._oauth2_return is not None) and (self._oauth2_return._refresh_token is not None) and (self._client_id is not None): phoenix_request_headers: dict = {} phoenix_request_headers["Content-Type"] = "application/x-www-form-urlencoded" phoenix_request_headers["Cache-Control"] = "no-cache" phoenix_request_body = "grant_type=refresh_token" + \ "&client_id=" + self.get_client_id() + \ "&refresh_token=" + self.oauth2_return.get_refresh_token() response = requests.post("https://" + self.get_endpoint() + "/connect/token", headers = phoenix_request_headers, data = phoenix_request_body, verify = verify ) else: msg = messages.ERROR_AUTHENTICATION_NO_REFRESH_TOKEN_OR_CLIENT_ID logger.error(msg) raise common.PAWException(msg) if response.status_code == 200: try: response_oauth2_return = oauth2_return_from_dict(response.json()) except: msg = messages.ERROR_AUTHENTICATION_PHOENIX_RETURN_NOT_OAUTH2RETURN.format("/connect/token", response.json()) logger.error(msg) raise common.PAWException(msg) if response_oauth2_return.error is None: self.set_jwt_token(response_oauth2_return.access_token) self.set_oauth2_return(response_oauth2_return) msg = messages.INFO_AUTHENTICATION_TOKEN_REFRESH_SUCCESS logger.info(msg) else: msg = messages.ERROR_AUTHENTICATION_PHOENIX_REFRESH_200_RETURN_ERROR.format("/connect/token", response_oauth2_return.error) logger.error(msg) raise common.PAWException(msg) else: msg = messages.ERROR_AUTHENTICATION_PHOENIX_NOT_SUCCESSFUL.format("/connect/token", str(response)) logger.error(msg) raise common.PAWException(msg)
def __init__(self, host: str = constants.CLIENT_PAIRS_URL, username: str = None, api_key: str = None, api_key_file: str = "auth/oauth2.txt", client_id: str = "ibm-pairs", endpoint: str = "auth-b2b-twc.ibm.com", jwt_token: str = None, ): self._host = common.strip_protocol(host) self._username = username self._api_key = api_key self._api_key_file = api_key_file self._client_id = client_id self._endpoint = endpoint self._jwt_token = jwt_token self._oauth2_return = OAuth2Return() if ((self._api_key is None) and (self._username is not None)): try: self.set_credentials_from_file(self._username, self._api_key_file, self._host ) except: msg = messages.INFO_AUTHENTICATION_API_KEY_NOT_FOUND_IN_FILE.format(self._username, self._api_key_file, self._host) logger.info(msg) if (self._api_key is not None): try: self.get_auth_token(api_key = self._api_key, client_id = self._client_id, endpoint = self._endpoint ) except Exception as ex: msg = messages.INFO_AUTHENTICATION_COULD_NOT_GET_AUTH_TOKEN.format(api_key, ex) logger.info(msg) if self._jwt_token is None: msg = messages.ERROR_AUTHENTICATION_FAILED.format("JWT token") logger.error(msg) raise common.PAWException(msg)
def check_list(l: Any) -> list: ''' The method checks if the input value is of type list. :param l: The input value to check. :type l: list :returns: The input value. :rtype: list :raises Exception: If the type of 'l' is not 'list'. ''' try: assert isinstance(l, list) except: msg = messages.ERROR_COMMON_CHECK_WRONG_TYPE.format( type(l), str(l), 'list') logger.error(msg) raise PAWException(msg) return l
def check_dict(d: Any) -> dict: ''' The method checks if the input value is of type dict. :param d: The input value to check. :type d: dict :returns: The input value. :rtype: dict :raises Exception: If the type of 'd' is not 'dict'. ''' try: assert isinstance(d, dict) except: msg = messages.ERROR_COMMON_CHECK_WRONG_TYPE.format( type(d), str(d), 'dict') logger.error(msg) raise PAWException(msg) return d
def from_json(oauth2_return_json: Any): """ Create an OAuth2Return object from json (dictonary or str). :param oauth2_return_dict: A json dictionary that contains the keys of an OAuth2Return or a string representation of a json dictionary. :type oauth2_return_dict: Any :rtype: ibmpairs.authentication.OAuth2Return :raises Exception: if not a dictionary or a string. """ if isinstance(oauth2_return_json, dict): oauth2_return = OAuth2Return.from_dict(oauth2_return_json) elif isinstance(oauth2_return_json, str): oauth2_return_dict = json.loads(oauth2_return_json) oauth2_return = OAuth2Return.from_dict(oauth2_return_dict) else: msg = messages.ERROR_FROM_JSON_TYPE_NOT_RECOGNIZED.format(type(oauth2_return_json), "oauth2_return_json") logger.error(msg) raise common.PAWException(msg) return oauth2_return
def from_json(basic_json: Any): """ Create an Basic object from json (dictonary or str). :param basic_dict: A json dictionary that contains the keys of an Basic or a string representation of a json dictionary. :type basic_dict: Any :rtype: ibmpairs.authentication.Basic :raises Exception: if not a dictionary or a string. """ if isinstance(basic_json, dict): basic = Basic.from_dict(basic_json) elif isinstance(basic_json, str): basic_dict = json.loads(basic_json) basic = Basic.from_dict(basic_dict) else: msg = messages.ERROR_FROM_JSON_TYPE_NOT_RECOGNIZED.format(type(basic_json), "basic_json") logger.error(msg) raise common.PAWException(msg) return basic
def check_class(instance: Any, class_type: Type[T]) -> Any: """ The method checks if a provided 'instance' is of type 'class_type' with the intention of usage to check classes. :param instance: The input value to check. :type istance: Any :param class_type: The input type to check the input value against. :type class_type: Type[T] :returns: The input value. :rtype: Any :raises Exception: If the value of 'instance' is not type 'class_type'. """ try: assert isinstance(instance, class_type) except: msg = messages.ERROR_COMMON_CHECK_CLASS.format(type(instance), type(class_type)) logger.error(msg) raise PAWException(msg) return instance
def __init__(self, host: str = constants.CLIENT_PAIRS_URL, username: str = None, password: str = None, password_file: str = "auth/basic.txt" ): self._host = common.strip_protocol(host) self._username = username self._password = password self._password_file = password_file if ((self._password is None) and (self._username is not None)): try: self.set_credentials_from_file(self._username, self._password_file, self._host) except Exception as e: msg = messages.INFO_AUTHENTICATION_PASSWORD_NOT_FOUND_IN_FILE.format(self._username, self._password_file, self._host) logger.info(msg) if (self._password is None) or (self._username is None): msg = messages.ERROR_AUTHENTICATION_FAILED.format('username and password') logger.error(msg) raise common.PAWException(msg)
def check_bool(b: Any) -> bool: ''' The method checks if a boolean value, or a string or int that can validly be inferred to be boolean is found. If 'true' or 'false' (to lowercase) or '0' or '1' are found, they are transformed appropriately to a bool. :param b: The input value to check. :type b: Any :returns: A boolean of appropriate value 'True' or 'False' :rtype: bool :raises Exception: If the type of 'b' is not in ['bool', 'string' or 'int']. If the value of 'b' is a string but not (when converted to lowercase) 'true' or 'false'. If the value of 'b' is an integer but not '1' or '0'. ''' bo = None if isinstance(b, bool): bo = b elif isinstance(b, str): if b.lower() == 'true': bo = True msg = messages.INFO_COMMON_CHECK_BOOL_CONVERSION.format( type(b), str(b), 'True') logger.info(msg) elif b.lower() == 'false': bo = False msg = messages.INFO_COMMON_CHECK_BOOL_CONVERSION.format( type(b), str(b), 'False') logger.info(msg) else: msg = messages.ERROR_COMMON_CHECK_BOOL_STRING_NOT_BOOL.format( str(b)) logger.error(msg) raise PAWException(msg) elif isinstance(b, int): if b == 1: bo = True msg = messages.INFO_COMMON_CHECK_BOOL_CONVERSION.format( type(b), str(b), 'True') logger.info(msg) elif b == 0: bo = False msg = messages.INFO_COMMON_CHECK_BOOL_CONVERSION.format( type(b), str(b), 'False') logger.info(msg) else: msg = messages.ERROR_COMMON_CHECK_BOOL_INT_NOT_BOOL.format(str(b)) logger.error(msg) raise PAWException(msg) else: msg = messages.ERROR_COMMON_CHECK_BOOL.format(type(bo), str(bo)) logger.error(msg) raise PAWException(msg) return bo
def check_float(f: Any): ''' The method checks if the input value is of type float, if the input type is an 'int' or 'str' a cast is attempted. :param f: The input value to check. :type f: float :returns: The input value. :rtype: float :raises Exception: If the type of 'f' is not 'float' or 'int' or 'str'. If the input value cannot be cast to 'float'. ''' fl = None if isinstance(f, float): fl = f elif isinstance(f, str): try: fl = float(f) except: msg = messages.ERROR_COMMON_STR_TO_FLOAT.format(f) logger.error(msg) raise PAWException(msg) elif isinstance(f, int): try: fl = float(f) except: msg = messages.ERROR_COMMON_INT_TO_FLOAT.format(f) logger.error(msg) raise PAWException(msg) else: msg = messages.ERROR_COMMON_CHECK_FLOAT.format(type(f), str(f)) logger.error(msg) raise PAWException(msg) return fl
def add_dashboard_layer( query_registration: QueryRegistrationReturn, name: str, client=None, headers=None, host=None, style_properties={ 'palette': { 'COLOR_STEPS': [{ 'step': -1, 'rgba': [0, 0, 8, 255] }, { 'step': 0, 'rgba': [11, 0, 251, 255] }, { 'step': .2, 'rgba': [236, 0, 34, 255] }, { 'step': .4, 'rgba': [250, 93, 7, 255] }, { 'step': .6, 'rgba': [250, 249, 0, 255] }, { 'step': .8, 'rgba': [0, 239, 0, 255] }, { 'step': 1, 'rgba': [1, 49, 1, 255] }] }, 'unit': 'C', 'isInterpolated': True, 'extendMinimumColor': False, 'extendMaximumColor': True, 'invalidDataValue': -9999 }): """ A method to add a dashboard layer to the IBM Environmental Intelligence Suite (EIS) dashboard. :param query_registration: A query registration result from a successful EIS registration. :type query_registration: ibmpairs.dashboard.QueryRegistrationReturn :param name: A dashboard layer name. :type name: str :param client: (Optional) An IBM PAIRS Client. :type client: ibmpairs.client.Client :param headers: (Optional) Headers for the request. :type headers: str :param host: (Optional) A host for the registration. :type host: str :param style_properties: (Optional) A dictionary of style properties for the dashboard layer. :type style_properties: dict :raises Exception: If no client is provided or found Globally in the environment, if response is not 200. """ if (headers is None): headers = constants.CLIENT_JSON_HEADER if (host is None): host = constants.PHOENIX_ADD_DASHBOARD_LAYER if (client is None): client = common.set_client( input_client=client, global_client=client_module.GLOBAL_PAIRS_CLIENT) client.set_host(host) bodyJson = { 'VIEWERSHIP_ROLE': 'ALL', 'CONFIG_BLOCK': { 'id': name, 'modelRegistryId': None, 'displayName': name, 'provider': None, 'layerType': 'grid', 'isSelected': False, 'isActive': False, 'enableValidity': False, 'lastUpdatedUtc': None, 'coverageArea': 'Custom', 'dataAttributes': { 'url': 'https://foundation.agtech.ibm.com/v2', 'uuid': query_registration.analytics_uuid }, 'menuIconUrl': None, 'legendUrl': '', 'styleProperties': style_properties } } bodyJsonString = json.dumps(bodyJson) try: response = client.put(host, body=bodyJsonString, headers=headers) if response.status_code != 200: try: msg = json.dumps(response.json()) except: msg = str(response.status_code) logger.error(msg) raise common.PAWException(msg) except Exception as ex: raise ex finally: # set client back to pointing at PAIRS client.set_host(constants.CLIENT_PAIRS_URL)
def get_auth_token(self, api_key=None, client_id=None, endpoint=None): ''' The method submits a request to the authentication system and obtains a response. :param api_key: An api key for the authentication system. :type api_key: str :param client_id: A client id for the authentication system. :type client_id: str :param endpoint: The authentication endpoint. :type endpoint: str :returns: None :rtype: None ''' response = None response_oauth2_return = None if api_key is not None: self.set_api_key(api_key) if client_id is not None: self.set_client_id(client_id) if endpoint is not None: self.set_endpoint(endpoint) if (self._api_key is not None) and (self._client_id is not None): phoenix_request_headers: dict = {} phoenix_request_headers["Content-Type"] = "application/json" phoenix_request_headers["Cache-Control"] = "no-cache" phoenix_request_body: dict = {} phoenix_request_body["apiKey"] = self.get_api_key() phoenix_request_body["clientId"] = self.get_client_id() phoenix_request_body_json = json.dumps(phoenix_request_body) response = requests.post("https://" + self.get_endpoint() + "/Auth/GetBearerForClient", headers=phoenix_request_headers, data=phoenix_request_body_json) else: msg = messages.ERROR_AUTHENTICATION_NO_API_KEY_OR_CLIENT_ID logger.error(msg) raise common.PAWException(msg) if response.status_code == 200: try: response_oauth2_return = oauth2_return_from_dict( response.json()) except Exception as ex: msg = messages.ERROR_AUTHENTICATION_PHOENIX_RETURN_NOT_OAUTH2RETURN.format( response.json(), ex) logger.error(msg) raise common.PAWException(msg) if response_oauth2_return.error is None: self.set_jwt_token(response_oauth2_return.access_token) self.set_oauth2_return(response_oauth2_return) else: msg = messages.ERROR_AUTHENTICATION_PHOENIX_200_RETURN_ERROR.format( response_oauth2_return.error) logger.error(msg) raise common.PAWException(msg) else: msg = messages.ERROR_AUTHENTICATION_PHOENIX_NOT_SUCCESSFUL.format( str(response)) logger.error(msg) raise common.PAWException(msg)
def register_query(query, query_name: str, client: client_module.Client = None, host: str = None): """ A method to register a PAIRS Query with the IBM Environmental Intelligence Suite (EIS) dashboard. :param query: A PAIRS Query. :type query: ibmpairs.query.Query or dict or str :param query_name: A query name. :type query_name: str :param client: (Optional) An IBM PAIRS Client. :type client: ibmpairs.client.Client :param host: (Optional) A host for the registration. :type host: str :returns: A QueryRegistrationReturn and a Query. :rtype: ibmpairs.dashboard.QueryRegistrationReturn, ibmpairs.query.Query :raises Exception: If no client is provided or found Globally in the environment, if query type is not ibmpairs.query.Query or dict or str, if response is not 200, if object conversions fail. """ if (host is None): host = constants.EIS_REGISTER_QUERY_URL if (client is None): client = common.set_client( input_client=client, global_client=client_module.GLOBAL_PAIRS_CLIENT) client.set_host(host) if isinstance(query, query_module.Query): query_body = query.to_json() elif isinstance(query, dict): query_body = json.dumps(query) elif isinstance(query, str): query_body = query else: msg = messages.ERROR_QUERY_TYPE_NOT_RECOGNIZED.format(type(query)) logger.error(msg) raise common.PAWException(msg) bodyJson = {"pairsPayload": query_body, "analyticsName": query_name} bodyJsonString = json.dumps(bodyJson) try: response = client.post(host, body=bodyJsonString) if response.status_code != 200: try: msg = json.dumps(response.json()) except: msg = str(response.status_code) logger.error(msg) raise common.PAWException(msg) query_registration = QueryRegistrationReturn.from_dict( response.json()[0]) query_return = query_module.QueryResponse( id=query_registration.base_computation_id) if isinstance(query, query_module.Query): query_obj = query elif isinstance(query, dict): query_obj = query_module.query_from_dict(query) else: query_obj = query_module.query_from_dict(query) query_obj.submit_response = query_return query_obj.id = query_registration.base_computation_id #query_result = query_module.QueryResult(client=client, query=query_obj, query_return=query_return) return query_registration, query_obj except Exception as ex: raise ex finally: # set client back to pointing at PAIRS client.set_host(constants.CLIENT_PAIRS_URL)