Source code for ibm_watson_machine_learning.shiny

#  -----------------------------------------------------------------------------------------
#  (C) Copyright IBM Corp. 2019-2024.
#  https://opensource.org/licenses/BSD-3-Clause
#  -----------------------------------------------------------------------------------------

from __future__ import print_function
import ibm_watson_machine_learning._wrappers.requests as requests
from ibm_watson_machine_learning.utils import DATA_ASSETS_DETAILS_TYPE, modify_details_for_script_and_shiny
from ibm_watson_machine_learning.metanames import ShinyMetaNames
from ibm_watson_machine_learning.wml_resource import WMLResource
from ibm_watson_machine_learning.wml_client_error import WMLClientError, ApiRequestFailure, ForbiddenActionForGitBasedProject, UnexpectedType
import os
import warnings

_DEFAULT_LIST_LENGTH = 50


[docs] class Shiny(WMLResource): """Store and manage shiny assets.""" ConfigurationMetaNames = ShinyMetaNames() """MetaNames for Shiny Assets creation.""" def __init__(self, client): WMLResource.__init__(self, __name__, client) self._ICP = client.ICP
[docs] def get_details(self, shiny_uid=None): """Get shiny asset details. If no shiny_uid is passed, details for all shiny assets will be returned. :param shiny_uid: Unique id of shiny asset :type shiny_uid: str, optional :return: metadata of the stored shiny asset :rtype: - **dict** - if runtime_uid is not None - **{"resources": [dict]}** - if runtime_uid is None **Example** .. code-block:: python shiny_details = client.shiny.get_details(shiny_uid) """ def get_required_elements(response): if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: return response else: response = modify_details_for_script_and_shiny(response) final_response = { "metadata": response[u'metadata'], "entity": {} } return final_response return self._get_asset_based_resource(shiny_uid, 'shiny_asset', get_required_elements)
[docs] def store(self, meta_props, file_path): """Create a shiny asset and uploads content to it. :param meta_props: metadata of shiny asset :type meta_props: dict :param file_path: path to the content file to be uploaded :type file_path: str :return: metadata of the stored shiny asset :rtype: dict **Example** .. code-block:: python meta_props = { client.shiny.ConfigurationMetaNames.NAME: "shiny app name" } shiny_details = client.shiny.store(meta_props, file_path="/path/to/file") """ if self._client.project_type == 'local_git_storage': raise ForbiddenActionForGitBasedProject(reason="Storing Shiny apps is not supported for git based project.") WMLResource._chk_and_block_create_update_for_python36(self) Shiny._validate_type(file_path, u'file_path', str, True) shiny_meta = self.ConfigurationMetaNames._generate_resource_metadata( meta_props, with_validation=True, client=self._client ) response = self._create_asset(shiny_meta, file_path) if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: return response else: final_response = { "metadata": response[u'metadata'], "entity": {} } return final_response
def _create_asset(self, shiny_meta, file_path): ##Step1: Create a shiny asset name = shiny_meta['metadata'][u'name'] desc = "" if shiny_meta['metadata'].get('description'): desc = shiny_meta['metadata'][u'description'] shiny_sw_spec_id = None if shiny_meta.get('software_spec_uid'): shiny_sw_spec_id = shiny_meta[u'software_spec_uid'] shiny_sw_specs = [] deprecated_shiny_sw_specs = [] if self._client.CPD_version >= 4.8: for sw_spec in self._client.software_specifications.get_details()['resources']: if sw_spec.get('metadata', {}).get('life_cycle', {}): if 'shiny' in sw_spec['metadata']['name'] or 'rstudio' in sw_spec['metadata']['name']: if ('retired' or 'deprecated' or 'constricted') not in sw_spec['metadata']['life_cycle']: shiny_sw_specs.append(sw_spec['metadata']['name']) elif 'deprecated' in sw_spec['metadata']['life_cycle']: deprecated_shiny_sw_specs.append(sw_spec['metadata']['name']) elif self._client.CPD_version >= 4.6: shiny_sw_specs = ('rstudio_r4.2',) deprecated_shiny_sw_specs = ('shiny-r3.6',) else: shiny_sw_specs = ('shiny-r3.6',) deprecated_shiny_sw_specs = () shiny_sw_spec_ids = [self._client.software_specifications.get_id_by_name(sw_name) for sw_name in shiny_sw_specs] deprecated_shiny_sw_spec_ids = [self._client.software_specifications.get_id_by_name(sw_name) for sw_name in deprecated_shiny_sw_specs] if shiny_sw_spec_id and shiny_sw_spec_id not in shiny_sw_spec_ids + deprecated_shiny_sw_spec_ids: raise WMLClientError( f"For R Shiny assets, only base software specs {','.join(shiny_sw_specs)} " "are supported. Specify " "the id you get via " "self._client.software_specifications.get_id_by_name(sw_name)") elif shiny_sw_spec_id and shiny_sw_spec_id in deprecated_shiny_sw_spec_ids: warnings.warn("Provided software spec is deprecated for R Shiny assets. " f"Only base software specs {','.join(shiny_sw_specs)} " "are supported. Specify " "the id you get via " "self._client.software_specifications.get_id_by_name(sw_name)") if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: asset_meta = { "metadata": { "name": name, "description": desc, "asset_type": "shiny_asset", "origin_country": "us", "asset_category": "USER" } } else: asset_meta = { "metadata": { "name": name, "description": desc, "asset_type": "shiny_asset", "origin_country": "us", "asset_category": "USER" }, "entity": { "shiny_asset": { "ml_version": "4.0.0" } } } if (self._client.CPD_version >= 4.6) and shiny_sw_spec_id: asset_meta['entity']['shiny_asset']['software_spec'] = \ {"base_id": shiny_sw_spec_id} base_shiny_asset = { "fields": [ { "key": "name", "type": "string", "is_array": False, "is_searchable_across_types": False }, { "key": "entity", "type": "object", "is_array": False, "is_searchable_across_types": False } ], "relationships": [], "name": "shiny_asset", "version": 1 } #Step1 : Create an asset print("Creating Shiny asset...") if self._client.WSD: # For WSD the asset creation is done within _wsd_create_asset function using polyglot # Thus using the same for data_assets type meta_props = { "name": name } details = Shiny._wsd_create_asset(self, "shiny_asset", asset_meta, meta_props, file_path, user_archive_file=True) return self._get_required_element_from_response(details) else: creation_response = "" if not self._ICP or self._client.ICP_PLATFORM_SPACES: creation_response = requests.post( self._client.service_instance._href_definitions.get_data_assets_href(), headers=self._client._get_headers(), params = self._client._params(), json=asset_meta ) else: # Until global asset for shiny is created asset_type_response = requests.post( self._client.service_instance._href_definitions.get_wsd_asset_type_href() + '?', headers=self._client._get_headers(), json=base_shiny_asset, params=self._client._params() ) if asset_type_response.status_code == 201 or asset_type_response.status_code == 409: creation_response = requests.post( self._client.service_instance._href_definitions.get_data_assets_href(), headers=self._client._get_headers(), json=asset_meta, params=self._client._params() ) shiny_details = self._handle_response(201, u'creating new asset', creation_response) #Step2: Create attachment if creation_response.status_code == 201: asset_id = shiny_details["metadata"]["asset_id"] attachment_meta = { "asset_type": "shiny_asset", "name": "attachment_"+asset_id } attachment_response = requests.post( self._client.service_instance._href_definitions.get_attachments_href(asset_id), headers=self._client._get_headers(), params=self._client._params(), json=attachment_meta ) attachment_details = self._handle_response(201, u'creating new attachment', attachment_response) if attachment_response.status_code == 201: attachment_id = attachment_details["attachment_id"] attachment_url = attachment_details["url1"] #Step3: Put content to attachment try: with open(file_path, 'rb') as f: if not self._ICP: put_response = requests.put( attachment_url, data=f.read(), # files = f ) else: put_response = requests.put( self._wml_credentials['url'] + attachment_url, files={'file': (name, f, 'application/octet-stream')} ) except Exception as e: deletion_response = requests.delete( self._client.service_instance._href_definitions.get_data_asset_href(asset_id), params=self._client._params(), headers=self._client._get_headers() ) print(deletion_response.status_code) raise WMLClientError("Failed while reading a file", e) if put_response.status_code == 201 or put_response.status_code == 200: # Step4: Complete attachment complete_response = requests.post( self._client.service_instance._href_definitions.get_attachment_complete_href(asset_id, attachment_id), headers=self._client._get_headers(), params = self._client._params() ) if complete_response.status_code == 200: print("SUCCESS") return self._get_required_element_from_response(shiny_details) else: self._delete(asset_id) raise WMLClientError("Failed while creating a shiny asset. Try again.") else: self._delete(asset_id) raise WMLClientError("Failed while creating a shiny asset. Try again.") else: print("SUCCESS") return self._get_required_element_from_response(shiny_details) else: raise WMLClientError("Failed while creating a shiny asset. Try again.")
[docs] def list(self, limit=None, return_as_df=True): """Print stored shiny assets in a table format. If limit is set to None there will be only first 50 records shown. :param limit: limit number of fetched records :type limit: int, optional :param return_as_df: determinate if table should be returned as pandas.DataFrame object, default: True :type return_as_df: bool, optional :return: pandas.DataFrame with listed shiny assets or None if return_as_df is False :rtype: pandas.DataFrame or None **Example** .. code-block:: python client.shiny.list() """ Shiny._validate_type(limit, u'limit', int, False) href = self._client.service_instance._href_definitions.get_search_shiny_href() data = { "query": "*:*" } if limit is not None: data.update({"limit": limit}) response = requests.post(href, params=self._client._params(), headers=self._client._get_headers(),json=data) self._handle_response(200, u'list assets', response) shiny_details = self._handle_response(200, u'list assets', response)["results"] space_values = [ (m[u'metadata'][u'name'], m[u'metadata'][u'asset_type'], m["metadata"]["asset_id"]) for m in shiny_details] table = self._list(space_values, [u'NAME', u'ASSET_TYPE', u'ASSET_ID'], None, _DEFAULT_LIST_LENGTH) if return_as_df: return table
[docs] def download(self, shiny_uid, filename, rev_uid=None): """Download the content of a shiny asset. :param shiny_uid: the Unique Id of the shiny asset to be downloaded :type shiny_uid: str :param filename: filename to be used for the downloaded file :type filename: str :param rev_uid: revision id :type rev_uid: str, optional :return: path to the downloaded shiny asset content :rtype: str **Example** .. code-block:: python client.shiny.download(shiny_uid, "shiny_asset.zip") """ if rev_uid is not None and not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: raise WMLClientError(u'Not applicable for this release') Shiny._validate_type(shiny_uid, u'shiny_uid', str, True) params = self._client._params() if rev_uid is not None: if not Shiny._validate_type(rev_uid, u'rev_id', [str, int], False): raise UnexpectedType('rev_uid', [str, int], type(rev_uid)) elif isinstance(rev_uid, int): warnings.warn("Parameter rev_uid as int is depreacted, should be of type str.") params.update({'revision_id': rev_uid}) import urllib asset_response = requests.get(self._client.service_instance._href_definitions.get_data_asset_href(shiny_uid), params=params, headers=self._client._get_headers()) shiny_details = self._handle_response(200, u'get shiny assets', asset_response) if self._WSD: attachment_url = shiny_details['attachments'][0]['object_key'] artifact_content_url = self._client.service_instance._href_definitions.get_wsd_model_attachment_href() + \ urllib.parse.quote('shiny_asset/' + attachment_url, safe='') r = requests.get(artifact_content_url, params=self._client._params(), headers=self._client._get_headers(), stream=True) if r.status_code != 200: raise ApiRequestFailure(u'Failure during {}.'.format("downloading shiny asset"), r) downloaded_asset = r.content try: with open(filename, 'wb') as f: f.write(downloaded_asset) print(u'Successfully saved shiny asset content to file: \'{}\''.format(filename)) return os.getcwd() + "/" + filename except IOError as e: raise WMLClientError(u'Saving shiny asset with artifact_url: \'{}\' to local file failed.'.format(filename), e) else: attachment_id = shiny_details["attachments"][0]["id"] response = requests.get(self._client.service_instance._href_definitions.get_attachment_href(shiny_uid,attachment_id), params=params, headers=self._client._get_headers()) if response.status_code == 200: attachment_signed_url = response.json()["url"] if 'connection_id' in shiny_details["attachments"][0]: att_response = requests.get(attachment_signed_url) else: if not self._ICP: att_response = requests.get(attachment_signed_url) else: att_response = requests.get(self._wml_credentials["url"]+attachment_signed_url) if att_response.status_code != 200: raise ApiRequestFailure(u'Failure during {}.'.format("downloading asset"), att_response) downloaded_asset = att_response.content try: with open(filename, 'wb') as f: f.write(downloaded_asset) print(u'Successfully saved shiny asset content to file: \'{}\''.format(filename)) return os.getcwd() + "/" + filename except IOError as e: raise WMLClientError(u'Saving shiny asset with artifact_url to local file: \'{}\' failed.'.format(filename), e) else: raise WMLClientError("Failed while downloading the shiny asset " + shiny_uid)
[docs] @staticmethod def get_id(shiny_details): """Get Unique Id of stored shiny asset. :param shiny_details: metadata of the stored shiny asset :type shiny_details: dict :return: Unique Id of stored shiny asset :rtype: str **Example** .. code-block:: python shiny_uid = client.shiny.get_id(shiny_details) """ return Shiny.get_uid(shiny_details)
[docs] @staticmethod def get_uid(shiny_details): """Get Unique Id of stored shiny asset. *Deprecated:* Use ``get_id(shiny_details)`` instead. :param shiny_details: metadata of the stored shiny asset :type shiny_details: dict :return: Unique Id of stored shiny asset :rtype: str **Example** .. code-block:: python shiny_uid = client.shiny.get_uid(shiny_details) """ Shiny._validate_type(shiny_details, u'shiny_details', object, True) Shiny._validate_type_of_details(shiny_details, DATA_ASSETS_DETAILS_TYPE) return WMLResource._get_required_element_from_dict(shiny_details, u'data_assets_details', [u'metadata', u'guid'])
[docs] @staticmethod def get_href(shiny_details): """Get url of stored shiny asset. :param shiny_details: stored shiny asset details :type shiny_details: dict :return: href of stored shiny asset :rtype: str **Example** .. code-block:: python shiny_details = client.shiny.get_details(shiny_uid) shiny_href = client.shiny.get_href(shiny_details) """ Shiny._validate_type(shiny_details, u'shiny_details', object, True) Shiny._validate_type_of_details(shiny_details, DATA_ASSETS_DETAILS_TYPE) return WMLResource._get_required_element_from_dict(shiny_details, u'shiny_details', [u'metadata', u'href'])
[docs] def update(self, shiny_uid, meta_props=None, file_path=None): """Update shiny with either metadata or attachment or both. :param shiny_uid: Shiny UID :type shiny_uid: str :param meta_props: changes to shiny metadata :type meta_props: dict, optional :param file_path: file path to new attachment :type file_path: str, optional :return: updated metadata of shiny asset :rtype: dict **Example** .. code-block:: python script_details = client.script.update(model_uid, meta, content_path) """ WMLResource._chk_and_block_create_update_for_python36(self) if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: raise WMLClientError(u'Not supported in this release') Shiny._validate_type(shiny_uid, 'shiny_uid', str, True) if meta_props is None and file_path is None: raise WMLClientError('Atleast either meta_props or file_path has to be provided') updated_details = None details = None url = self._client.service_instance._href_definitions.get_asset_href(shiny_uid) # STEPS # STEP 1. Get existing metadata # STEP 2. If meta_props provided, we need to patch meta # CAMS has meta and entity patching. 'name' and 'description' get stored in CAMS meta section # a. Construct meta patch string and call /v2/assets/<asset_id> to patch meta # STEP 3. If file_path provided, we need to patch the attachment # a. If attachment already exists for the script, delete it # b. POST call to get signed url for upload # c. Upload to the signed url # d. Mark upload complete # STEP 4. Get the updated script record and return # STEP 1 response = requests.get( url, params=self._client._params(), headers=self._client._get_headers() ) if response.status_code != 200: if response.status_code == 404: raise WMLClientError( u'Invalid input. Unable to get the details of shiny_uid provided.') else: raise ApiRequestFailure(u'Failure during {}.'.format("getting shiny asset to update"), response) details = self._handle_response(200, "Get shiny asset details", response) attachments_response = None # STEP 2a. # Patch meta if provided if meta_props is not None: self._validate_type(meta_props, u'meta_props', dict, True) meta_patch_payload = [] # Since we are dealing with direct asset apis, name and description is metadata patch if "name" in meta_props or "description" in meta_props: props_for_asset_meta_patch = {} for key in meta_props: if key == 'name' or key == 'description': props_for_asset_meta_patch.update({key: meta_props[key]}) meta_patch_payload = self.ConfigurationMetaNames._generate_patch_payload(details, props_for_asset_meta_patch, with_validation=True) if meta_patch_payload: meta_patch_url = self._client.service_instance._href_definitions.get_asset_href(shiny_uid) response_patch = requests.patch(meta_patch_url, json=meta_patch_payload, params=self._client._params(), headers=self._client._get_headers()) updated_details = self._handle_response(200, u'shiny patch', response_patch) if file_path is not None: if "attachments" in details and details[u'attachments']: current_attachment_id = details[u'attachments'][0][u'id'] else: current_attachment_id = None #STEP 3 attachments_response = self._update_attachment_for_assets("shiny_asset", shiny_uid, file_path, current_attachment_id) if attachments_response is not None and 'success' not in attachments_response: self._update_msg(updated_details) # Have to fetch again to reflect updated asset and attachment ids url = self._client.service_instance._href_definitions.get_asset_href(shiny_uid) response = requests.get( url, params=self._client._params(), headers=self._client._get_headers() ) if response.status_code != 200: if response.status_code == 404: raise WMLClientError( u'Invalid input. Unable to get the details of shiny_uid provided.') else: raise ApiRequestFailure(u'Failure during {}.'.format("getting shiny to update"), response) # response = self._handle_response(200, "Get shiny details", response) # # return self._get_required_element_from_response(response) response = self._get_required_element_from_response(self._handle_response(200, "Get shiny details", response)) if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: return response else: final_response = { "metadata": response[u'metadata'], "entity": {} } return final_response
def _update_msg(self, updated_details): if updated_details is not None: print("Could not update the attachment because of server error." " However metadata is updated. Try updating attachment again later") else: raise WMLClientError('Unable to update attachment because of server error. Try again later')
[docs] def delete(self, shiny_uid): """Delete a stored shiny asset. :param shiny_uid: Unique Id of shiny asset :type shiny_uid: str :return: status ("SUCCESS" or "FAILED") :rtype: str **Example** .. code-block:: python client.shiny.delete(shiny_uid) """ Shiny._validate_type(shiny_uid, u'shiny_uid', str, True) if (self._client.CLOUD_PLATFORM_SPACES or self._client.ICP_PLATFORM_SPACES) and \ self._if_deployment_exist_for_asset(shiny_uid): raise WMLClientError( u'Cannot delete shiny asset that has existing deployments. Please delete all associated deployments and try again') response = requests.delete(self._client.service_instance._href_definitions.get_asset_href(shiny_uid), params=self._client._params(), headers=self._client._get_headers()) if response.status_code == 200: return self._get_required_element_from_response(response.json()) else: return self._handle_response(204, u'delete assets', response)
[docs] def create_revision(self, shiny_uid): """Create revision for the given Shiny asset. Revisions are immutable once created. The metadata and attachment at `script_uid` is taken and a revision is created out of it. :param shiny_uid: shiny asset ID :type shiny_uid: str :return: stored shiny asset revisions metadata :rtype: dict **Example** .. code-block:: python shiny_revision = client.shiny.create_revision(shiny_uid) """ WMLResource._chk_and_block_create_update_for_python36(self) if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: raise WMLClientError(u'Not supported in this release') ##For CP4D, check if either space or project ID is set self._client._check_if_either_is_set() Shiny._validate_type(shiny_uid, u'shiny_uid', str, True) print("Creating shiny revision...") # # return self._get_required_element_from_response( # self._create_revision_artifact_for_assets(shiny_uid, 'Shiny')) response = self._get_required_element_from_response( self._create_revision_artifact_for_assets(shiny_uid, 'Shiny')) if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: return response else: final_response = { "metadata": response[u'metadata'], "entity": {} } return final_response
[docs] def list_revisions(self, shiny_uid, limit=None, return_as_df=True): """Print all revisions for the given shiny asset uid in a table format. :param shiny_uid: stored shiny asset ID :type shiny_uid: str :param limit: limit number of fetched records :type limit: int, optional :param return_as_df: determinate if table should be returned as pandas.DataFrame object, default: True :type return_as_df: bool, optional :return: pandas.DataFrame with listed shiny revisions or None if return_as_df is False :rtype: pandas.DataFrame or None **Example** .. code-block:: python client.shiny.list_revisions(shiny_uid) """ if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: raise WMLClientError(u'Not supported in this release') ##For CP4D, check if either space or project ID is set self._client._check_if_either_is_set() Shiny._validate_type(shiny_uid, u'shiny_uid', str, True) url = self._client.service_instance._href_definitions.get_asset_href(shiny_uid) + "/revisions" # /v2/assets/{asset_id}/revisions returns 'results' object shiny_resources = self._get_with_or_without_limit(url, limit, 'List Shiny revisions', summary=None, pre_defined=None)[u'resources'] shiny_values = [ (m[u'metadata'][u'asset_id'], m[u'metadata'][u'revision_id'], m[u'metadata'][u'name'], m[u'metadata'][u'commit_info'][u'committed_at']) for m in shiny_resources] table = self._list(shiny_values, [u'GUID', u'REVISION_ID', u'NAME', u'REVISION_COMMIT'], limit, _DEFAULT_LIST_LENGTH) if return_as_df: return table
[docs] def get_revision_details(self, shiny_uid=None, rev_uid=None): """Get metadata of `shiny_uid` revision. :param shiny_uid: shiny asset ID :type shiny_uid: str, optional :param rev_uid: revision ID, if this parameter is not provided, returns latest revision if existing else error :type rev_uid: str, optional :return: stored shiny(s) metadata :rtype: dict **Example** .. code-block:: python shiny_details = client.shiny.get_revision_details(shiny_uid, rev_uid) """ if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: raise WMLClientError(u'Not supported in this release') ##For CP4D, check if either space or project ID is set self._client._check_if_either_is_set() Shiny._validate_type(shiny_uid, u'shiny_uid', str, True) if rev_uid is None: rev_uid = 'latest' else: if not Shiny._validate_type(rev_uid, u'rev_uid', [str, int], False): raise UnexpectedType('rev_uid', [str, int], type(rev_uid)) elif isinstance(rev_uid, int): warnings.warn("Parameter rev_uid as int is depreacted, should be of type str.") url = self._client.service_instance._href_definitions.get_asset_href(shiny_uid) # return self._get_required_element_from_response(self._get_with_or_without_limit(url, # limit=None, # op_name="asset_revision", # summary=None, # pre_defined=None, # revision=rev_uid)) resources = self._get_with_or_without_limit(url, limit=None, op_name="asset_revision", summary=None, pre_defined=None, revision=rev_uid)['resources'] responses = [self._get_required_element_from_response(resource) for resource in resources] if not self._client.CLOUD_PLATFORM_SPACES and not self._client.ICP_PLATFORM_SPACES: return responses else: final_responses = [{ "metadata": response[u'metadata'], "entity": {} } for response in responses] return final_responses
def _delete(self, shiny_uid): Shiny._validate_type(shiny_uid, u'shiny_uid', str, True) response = requests.delete(self._client.service_instance._href_definitions.get_asset_href(shiny_uid), params=self._client._params(), headers=self._client._get_headers()) # def get_href(self, shiny_uid): # """ # Get metadata of stored space(s). If space UID is not specified, it returns all the spaces metadata. # # **Parameters** # # .. important:: # #. **space_uid**: Space UID (optional)\n # **type**: str\n # #. **limit**: limit number of fetched records (optional)\n # **type**: int\n # # **Output** # # .. important:: # **returns**: metadata of stored space(s)\n # **return type**: dict # dict (if UID is not None) or {"resources": [dict]} (if UID is None)\n # # .. note:: # If UID is not specified, all spaces metadata is fetched\n # # **Example** # # >>> space_details = client.spaces.get_details(space_uid) # >>> space_details = client.spaces.get_details() # """ # # # Assets._validate_type(shiny_uid, u'shiny_uid', str, True) # # response = requests.get(self._client.service_instance._href_definitions.get_data_asset_href(shiny_uid), params=self._client._params(), # headers=self._client._get_headers()) # # if response.status_code == 200: # return response.json()["href"] # else: # return self._handle_response(200, u'spaces assets', response) def _get_required_element_from_response(self, response_data): WMLResource._validate_type(response_data, u'shiny', dict) revision_id = None try: if self._client.default_space_id is not None: metadata = {'space_id': response_data['metadata']['space_id'], 'guid': response_data['metadata']['asset_id'], 'href': response_data['href'], 'name': response_data[u'metadata'][u'name'], 'asset_type': response_data['metadata']['asset_type'], 'created_at': response_data['metadata']['created_at'], 'last_updated_at': response_data['metadata']['usage']['last_updated_at'] } if self._client.CLOUD_PLATFORM_SPACES or self._client.ICP_PLATFORM_SPACES: if "revision_id" in response_data[u'metadata']: revision_id = response_data[u'metadata'][u'revision_id'] metadata.update({'revision_id': response_data[u'metadata'][u'revision_id']}) if "attachments" in response_data and response_data[u'attachments']: metadata.update({'attachment_id': response_data[u'attachments'][0][u'id']}) if "commit_info" in response_data[u'metadata'] and revision_id is not None: metadata.update( {'revision_commit_date': response_data[u'metadata'][u'commit_info']['committed_at']}) new_el = {'metadata': metadata, 'entity': response_data['entity'] } elif self._client.default_project_id is not None: if self._client.WSD: href = self._client.service_instance._href_definitions.get_base_asset_href(response_data['metadata']['asset_id']) + "?" + "project_id=" + response_data['metadata']['project_id'] metadata = {'project_id': response_data['metadata']['project_id'], 'guid': response_data['metadata']['asset_id'], 'href': href, 'name': response_data[u'metadata'][u'name'], 'asset_type': response_data['metadata']['asset_type'], 'created_at': response_data['metadata']['created_at'] } if self._client.WSD_20 is not None: if "revision_id" in response_data[u'metadata']: revision_id = response_data[u'metadata'][u'revision_id'] metadata.update({'revision_id': response_data[u'metadata'][u'revision_id']}) if "attachments" in response_data and response_data[u'attachments']: metadata.update({'attachment_id': response_data[u'attachments'][0][u'id']}) if "commit_info" in response_data[u'metadata'] and revision_id is not None: metadata.update( {'revision_commit_date': response_data[u'metadata'][u'commit_info']['committed_at']}) new_el = {'metadata': metadata, 'entity': response_data['entity'] } if 'usage' in response_data['metadata']: new_el['metadata'].update( {'last_updated_at': response_data['metadata']['usage']['last_updated_at']}) else: new_el['metadata'].update( {'last_updated_at': response_data['metadata']['last_updated_at']}) else: metadata = {'project_id': response_data['metadata']['project_id'], 'guid': response_data['metadata']['asset_id'], 'href': response_data['href'], 'name': response_data[u'metadata'][u'name'], 'asset_type': response_data['metadata']['asset_type'], 'created_at': response_data['metadata']['created_at'], 'last_updated_at': response_data['metadata']['usage']['last_updated_at'] } if self._client.CLOUD_PLATFORM_SPACES or self._client.ICP_PLATFORM_SPACES: if "revision_id" in response_data[u'metadata']: revision_id = response_data[u'metadata'][u'revision_id'] metadata.update({'revision_id': response_data[u'metadata'][u'revision_id']}) if "attachments" in response_data and response_data[u'attachments']: metadata.update({'attachment_id': response_data[u'attachments'][0][u'id']}) if "commit_info" in response_data[u'metadata'] and revision_id is not None: metadata.update( {'revision_commit_date': response_data[u'metadata'][u'commit_info']['committed_at']}) new_el = {'metadata': metadata, 'entity': response_data['entity'] } if 'description' in response_data['metadata']: new_el[u'metadata'].update({'description': response_data[u'metadata'][u'description']}) if (self._client.CLOUD_PLATFORM_SPACES or self._client.ICP_PLATFORM_SPACES) and 'href' in response_data['metadata']: href_without_host = response_data['metadata']['href'].split('.com')[-1] new_el[u'metadata'].update({'href': href_without_host}) return new_el except Exception as e: raise WMLClientError("Failed to read Response from down-stream service: " + response_data.text)