def update_default_member(self, dimension_name, hierarchy_name=None, member_name=""): """ Update the default member of a hierarchy. Currently implemented through TI, since TM1 API does not supports default member updates yet. :param dimension_name: :param hierarchy_name: :param member_name: :return: """ from TM1py import ProcessService, CellService if hierarchy_name and not case_and_space_insensitive_equals( dimension_name, hierarchy_name): dimension = "{}:{}".format(dimension_name, hierarchy_name) else: dimension = dimension_name cells = {(dimension, 'hierarchy0', 'defaultMember'): member_name} CellService(self._rest).write_values( cube_name="}HierarchyProperties", cellset_as_dict=cells, dimensions=('}Dimensions', '}Hierarchies', '}HierarchyProperties')) return ProcessService(self._rest).execute_ti_code( lines_prolog="RefreshMdxHierarchy('{}');".format(dimension_name))
def update(self, hierarchy: Hierarchy, **kwargs) -> List[Response]: """ update a hierarchy. It's a two step process: 1. Update Hierarchy 2. Update Element-Attributes Function caters for Bug with Edge Creation: https://www.ibm.com/developerworks/community/forums/html/topic?id=75f2b99e-6961-4c71-9364-1d5e1e083eff :param hierarchy: instance of TM1py.Hierarchy :return: list of responses """ # functions returns multiple responses responses = list() # 1. Update Hierarchy url = format_url("/api/v1/Dimensions('{}')/Hierarchies('{}')", hierarchy.dimension_name, hierarchy.name) # Workaround EDGES: Handle Issue, that Edges cant be created in one batch with the Hierarchy in certain versions hierarchy_body = hierarchy.body_as_dict if self.version[0:8] in self.EDGES_WORKAROUND_VERSIONS: del hierarchy_body["Edges"] responses.append( self._rest.PATCH(url, json.dumps(hierarchy_body), **kwargs)) # 2. Update Attributes responses.append( self.update_element_attributes(hierarchy=hierarchy, **kwargs)) # Workaround EDGES if self.version[0:8] in self.EDGES_WORKAROUND_VERSIONS: from TM1py.Services import ProcessService process_service = ProcessService(self._rest) ti_function = "HierarchyElementComponentAdd('{}', '{}', '{}', '{}', {});" ti_statements = [ ti_function.format(hierarchy.dimension_name, hierarchy.name, edge[0], edge[1], hierarchy.edges[(edge[0], edge[1])]) for edge in hierarchy.edges ] responses.append( process_service.execute_ti_code(lines_prolog=ti_statements, **kwargs)) return responses
def write_to_message_log(self, level: str, message: str, **kwargs) -> None: """ :param level: string, FATAL, ERROR, WARN, INFO, DEBUG :param message: string :return: """ valid_levels = CaseAndSpaceInsensitiveSet( {'FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG'}) if level not in valid_levels: raise ValueError(f"Invalid level: '{level}'") from TM1py.Services import ProcessService process_service = ProcessService(self._rest) process = Process(name="", prolog_procedure="LogOutput('{}', '{}');".format( level, message)) success, status, _ = process_service.execute_process_with_return( process, **kwargs) if not success: raise RuntimeError( f"Failed to write to TM1 Message Log through unbound process. Status: '{status}'" )
def __init__(self, **kwargs): self._tm1_rest = RestService(**kwargs) # instantiate all Services self.annotations = AnnotationService(self._tm1_rest) self.cells = CellService(self._tm1_rest) self.chores = ChoreService(self._tm1_rest) self.cubes = CubeService(self._tm1_rest) self.dimensions = DimensionService(self._tm1_rest) self.elements = ElementService(self._tm1_rest) self.hierarchies = HierarchyService(self._tm1_rest) self.monitoring = MonitoringService(self._tm1_rest) self.power_bi = PowerBiService(self._tm1_rest) self.processes = ProcessService(self._tm1_rest) self.security = SecurityService(self._tm1_rest) self.server = ServerService(self._tm1_rest) self.subsets = SubsetService(self._tm1_rest) self.applications = ApplicationService(self._tm1_rest) self.views = ViewService(self._tm1_rest)
def _instantiate_services(self): self.annotations = AnnotationService(self._tm1_rest) self.cells = CellService(self._tm1_rest) self.chores = ChoreService(self._tm1_rest) self.cubes = CubeService(self._tm1_rest) self.dimensions = DimensionService(self._tm1_rest) self.elements = ElementService(self._tm1_rest) self.git = GitService(self._tm1_rest) self.hierarchies = HierarchyService(self._tm1_rest) self.monitoring = MonitoringService(self._tm1_rest) self.power_bi = PowerBiService(self._tm1_rest) self.processes = ProcessService(self._tm1_rest) self.security = SecurityService(self._tm1_rest) self.server = ServerService(self._tm1_rest) self.subsets = SubsetService(self._tm1_rest) self.applications = ApplicationService(self._tm1_rest) self.views = ViewService(self._tm1_rest) self.sandboxes = SandboxService(self._tm1_rest) self.git = GitService(self._tm1_rest)
def save_data(self, **kwargs) -> Response: from TM1py.Services import ProcessService ti = "SaveDataAll;" process_service = ProcessService(self._rest) return process_service.execute_ti_code(ti, **kwargs)
def save_data(self): from TM1py.Services import ProcessService ti = "SaveDataAll;" process_service = ProcessService(self._rest) process_service.execute_ti_code(ti)
def security_refresh(self): from TM1py.Services import ProcessService ti = "SecurityRefresh;" process_service = ProcessService(self._rest) process_service.execute_ti_code(ti)
def security_refresh(self, **kwargs) -> Response: from TM1py.Services import ProcessService ti = "SecurityRefresh;" process_service = ProcessService(self._rest) return process_service.execute_ti_code(ti, **kwargs)
def __init__(self, rest): super().__init__(rest) self._process_service = ProcessService(rest)
class SubsetService(ObjectService): """ Service to handle Object Updates for TM1 Subsets (dynamic and static) """ def __init__(self, rest): super().__init__(rest) self._process_service = ProcessService(rest) def create(self, subset, private=True): """ create subset on the TM1 Server :param subset: TM1py.Subset, the subset that shall be created :param private: boolean :return: string: the response """ subsets = "PrivateSubsets" if private else "Subsets" request = '/api/v1/Dimensions(\'{}\')/Hierarchies(\'{}\')/{}' \ .format(subset.dimension_name, subset.dimension_name, subsets) response = self._rest.POST(request, subset.body) return response def get(self, dimension_name, subset_name, private=True): """ get a subset from the TM1 Server :param dimension_name: string, name of the dimension :param subset_name: string, name of the subset :param private: Boolean :return: instance of TM1py.Subset """ subsets = "PrivateSubsets" if private else "Subsets" request = '/api/v1/Dimensions(\'{}\')/Hierarchies(\'{}\')/{}(\'{}\')?$expand=' \ 'Hierarchy($select=Dimension),' \ 'Elements($select=Name)&$select=*,Alias'.format(dimension_name, dimension_name, subsets, subset_name) response = self._rest.GET(request=request) return Subset.from_json(response) def get_all_names(self, dimension_name, hierarchy_name, private=True): """ get names of all private or public subsets in a hierarchy :param dimension_name: :param hierarchy_name: :param private: Boolean :return: List of Strings """ subsets = "PrivateSubsets" if private else "Subsets" request = '/api/v1/Dimensions(\'{}\')/Hierarchies(\'{}\')/{}?$select=Name' \ .format(dimension_name, hierarchy_name, subsets) response = self._rest.GET(request=request) subsets = json.loads(response)['value'] return [subset['Name'] for subset in subsets] def update(self, subset, private=True): """ update a subset on the TM1 Server :param subset: instance of TM1py.Subset. :param private: Boolean :return: response """ if private: # Just delete it and rebuild it, since there are no dependencies return self._update_private(subset) else: # Update it. Clear Elements with evil workaround return self._update_public(subset) def _update_private(self, subset): """ update a private subset on the TM1 Server :param subset: instance of TM1py.Subset :return: response """ # Delete it request = '/api/v1/Dimensions(\'{}\')/Hierarchies(\'{}\')/PrivateSubsets(\'{}\')' \ .format(subset.dimension_name, subset.dimension_name, subset.name) self._rest.DELETE(request, '') # Rebuild it return self.create(subset, True) def _update_public(self, subset): """ Update a public subset on the TM1 Server :param subset: instance of TM1py.Subset :return: response """ # clear elements of subset. evil workaround! Should be done through delete on the Elements Collection # (which is currently not supported 10.2.2 FP6) ti = "SubsetDeleteAllElements(\'{}\', \'{}\');".format(subset.dimension_name, subset.name) self._process_service.execute_ti_code(lines_prolog=ti, lines_epilog='') # update subset request = '/api/v1/Dimensions(\'{}\')/Hierarchies(\'{}\')/Subsets(\'{}\')' \ .format(subset.dimension_name, subset.dimension_name, subset.name) return self._rest.PATCH(request=request, data=subset.body) def delete(self, dimension_name, subset_name, private=True): """ Delete an existing subset on the TM1 Server :param dimension_name: String, name of the dimension :param subset_name: String, name of the subset :param private: Boolean :return: """ subsets = "PrivateSubsets" if private else "Subsets" request = '/api/v1/Dimensions(\'{}\')/Hierarchies(\'{}\')/{}(\'{}\')' \ .format(dimension_name, dimension_name, subsets, subset_name) response = self._rest.DELETE(request=request, data='') return response def exists(self, dimension_name, hierarchy_name, subset_name): """checks if subset exists as private and / or public :param dimension_name: :param hierarchy_name: :param subset_name: :return: 2 booleans: (Private subset exsits, Public subset exists) """ subset_types = collections.OrderedDict() subset_types['PrivateSubsets'] = False subset_types['Subsets'] = False for subset_type in subset_types: try: self._rest.GET("/api/v1/Dimensions('{}')/Hierarchies('{}')/{}('{}')" .format(dimension_name, hierarchy_name, subset_type, subset_name)) subset_types[subset_type] = True except TM1pyException as e: if e._status_code != 404: raise e return tuple(subset_types.values())