def __init__(self, rest): super().__init__(rest) self.hierarchies = HierarchyService(rest) self.subsets = SubsetService(rest)
class DimensionService(ObjectService): """ Service to handle Object Updates for TM1 Dimensions """ def __init__(self, rest: RestService): super().__init__(rest) self.hierarchies = HierarchyService(rest) self.subsets = SubsetService(rest) def create(self, dimension: Dimension, **kwargs) -> Response: """ Create a dimension :param dimension: instance of TM1py.Dimension :return: response """ # If Dimension exists. throw Exception if self.exists(dimension.name): raise RuntimeError("Dimension '{}' already exists".format( dimension.name)) # If not all subsequent calls successful -> undo everything that has been done in this function try: # Create Dimension, Hierarchies, Elements, Edges. url = "/api/v1/Dimensions" response = self._rest.POST(url, dimension.body, **kwargs) # Create ElementAttributes for hierarchy in dimension: if not case_and_space_insensitive_equals( hierarchy.name, "Leaves"): self.hierarchies.update_element_attributes( hierarchy, **kwargs) except TM1pyException as e: # undo everything if problem in step 1 or 2 if self.exists(dimension.name, **kwargs): self.delete(dimension.name) raise e return response def get(self, dimension_name: str, **kwargs) -> Dimension: """ Get a Dimension :param dimension_name: :return: """ url = format_url( "/api/v1/Dimensions('{}')?$expand=Hierarchies($expand=*)", dimension_name) response = self._rest.GET(url, **kwargs) return Dimension.from_json(response.text) def update(self, dimension: Dimension, **kwargs): """ Update an existing dimension :param dimension: instance of TM1py.Dimension :return: None """ # delete hierarchies that have been removed from the dimension object hierarchies_to_be_removed = CaseAndSpaceInsensitiveSet( *self.hierarchies.get_all_names(dimension.name, **kwargs)) for hierarchy in dimension.hierarchy_names: hierarchies_to_be_removed.discard(hierarchy) for hierarchy_name in hierarchies_to_be_removed: self.hierarchies.delete(dimension_name=dimension.name, hierarchy_name=hierarchy_name, **kwargs) # update all Hierarchies except for the implicitly maintained 'Leaves' Hierarchy for hierarchy in dimension: if not case_and_space_insensitive_equals(hierarchy.name, "Leaves"): if self.hierarchies.exists(hierarchy.dimension_name, hierarchy.name, **kwargs): self.hierarchies.update(hierarchy, **kwargs) else: self.hierarchies.create(hierarchy, **kwargs) def update_or_create(self, dimension: Dimension, **kwargs): """ update if exists else create :param dimension: :return: """ if self.exists(dimension_name=dimension.name, **kwargs): return self.update(dimension=dimension) else: return self.create(dimension=dimension) def delete(self, dimension_name: str, **kwargs) -> Response: """ Delete a dimension :param dimension_name: Name of the dimension :return: """ url = format_url("/api/v1/Dimensions('{}')", dimension_name) return self._rest.DELETE(url, **kwargs) def exists(self, dimension_name: str, **kwargs) -> bool: """ Check if dimension exists :return: """ url = format_url("/api/v1/Dimensions('{}')", dimension_name) return self._exists(url, **kwargs) def get_all_names(self, **kwargs) -> List[str]: """Ask TM1 Server for list with all dimension names :Returns: List of Strings """ response = self._rest.GET(url='/api/v1/Dimensions?$select=Name', **kwargs) dimension_names = list(entry['Name'] for entry in response.json()['value']) return dimension_names def execute_mdx(self, dimension_name: str, mdx: str, **kwargs) -> List: """ Execute MDX against Dimension. Requires }ElementAttributes_ Cube of the dimension to exist ! :param dimension_name: Name of the Dimension :param mdx: valid Dimension-MDX Statement :return: List of Element names """ warnings.warn( "execute_mdx() will be deprecated; use ElementService execute_set_mdx.", DeprecationWarning, stacklevel=2) mdx_skeleton = "SELECT " \ "{} ON ROWS, " \ "{{ [}}ElementAttributes_{}].DefaultMember }} ON COLUMNS " \ "FROM [}}ElementAttributes_{}]" mdx_full = mdx_skeleton.format(mdx, dimension_name, dimension_name) request = '/api/v1/ExecuteMDX?$expand=Axes(' \ '$filter=Ordinal eq 1;' \ '$expand=Tuples($expand=Members($select=Ordinal;$expand=Element($select=Name))))' payload = {"MDX": mdx_full} response = self._rest.POST(request, json.dumps(payload, ensure_ascii=False), **kwargs) raw_dict = response.json() return [ row_tuple['Members'][0]['Element']['Name'] for row_tuple in raw_dict['Axes'][0]['Tuples'] ] def create_element_attributes_through_ti(self, dimension: Dimension, **kwargs): """ :param dimension. Instance of TM1py.Objects.Dimension class :return: """ process_service = ProcessService(self._rest) for h in dimension: statements = [ "AttrInsert('{}', '', '{}', '{}');".format( dimension.name, ea.name, ea.attribute_type[0]) for ea in h.element_attributes ] process_service.execute_ti_code(lines_prolog=statements, **kwargs)
class DimensionService(ObjectService): """ Service to handle Object Updates for TM1 Dimensions """ def __init__(self, rest): super().__init__(rest) self.hierarchies = HierarchyService(rest) self.subsets = SubsetService(rest) def create(self, dimension): """ Create a dimension :param dimension: instance of TM1py.Dimension :return: response """ # If Dimension exists. throw Exception if self.exists(dimension.name): raise Exception("Dimension already exists") # If not all subsequent calls successfull -> undo everything that has been done in this function try: # Create Dimension, Hierarchies, Elements, Edges. request = "/api/v1/Dimensions" response = self._rest.POST(request, dimension.body) for hierarchy in dimension: if len(hierarchy.element_attributes) > 0: self.hierarchies.update(hierarchy) except TM1pyException as e: # undo everything if problem in step 1 or 2 if self.exists(dimension.name): self.delete(dimension.name) raise e return response def get(self, dimension_name): """ Get a Dimension :param dimension_name: :return: """ request = "/api/v1/Dimensions('{}')?$expand=Hierarchies($expand=*)".format( dimension_name) response = self._rest.GET(request) return Dimension.from_json(response.text) def update(self, dimension): """ Update an existing dimension :param dimension: instance of TM1py.Dimension :return: None """ # update all Hierarchies except for the implicitly maintained 'Leaves' Hierarchy for hierarchy in dimension: if hierarchy.name != "Leaves": if self.hierarchies.exists( dimension_name=hierarchy.dimension_name, hierarchy_name=hierarchy.name): self.hierarchies.update(hierarchy) else: self.hierarchies.create(hierarchy) def delete(self, dimension_name): """ Delete a dimension :param dimension_name: Name of the dimension :return: """ request = '/api/v1/Dimensions(\'{}\')'.format(dimension_name) return self._rest.DELETE(request) def exists(self, dimension_name): """ Check if dimension exists :return: """ request = "/api/v1/Dimensions('{}')".format(dimension_name) return self._exists(request) def get_all_names(self): """Ask TM1 Server for list with all dimension names :Returns: List of Strings """ response = self._rest.GET('/api/v1/Dimensions?$select=Name', '') dimension_names = list(entry['Name'] for entry in response.json()['value']) return dimension_names def execute_mdx(self, dimension_name, mdx): """ Execute MDX against Dimension. Requires }ElementAttributes_ Cube of the dimension to exist ! :param dimension_name: Name of the Dimension :param mdx: valid Dimension-MDX Statement :return: List of Element names """ mdx_skeleton = "SELECT " \ "{} ON ROWS, " \ "{{ [}}ElementAttributes_{}].DefaultMember }} ON COLUMNS " \ "FROM [}}ElementAttributes_{}]" mdx_full = mdx_skeleton.format(mdx, dimension_name, dimension_name) request = '/api/v1/ExecuteMDX?$expand=Axes(' \ '$filter=Ordinal eq 1;' \ '$expand=Tuples($expand=Members($select=Ordinal;$expand=Element($select=Name))))' payload = {"MDX": mdx_full} response = self._rest.POST(request, json.dumps(payload, ensure_ascii=False)) raw_dict = response.json() return [ row_tuple['Members'][0]['Element']['Name'] for row_tuple in raw_dict['Axes'][0]['Tuples'] ] def create_element_attributes_through_ti(self, dimension): """ :param dimension. Instance of TM1py.Objects.Dimension class :return: """ process_service = ProcessService(self._rest) for h in dimension: statements = [ "AttrInsert('{}', '', '{}', '{}');".format( dimension.name, ea.name, ea.attribute_type[0]) for ea in h.element_attributes ] process_service.execute_ti_code(lines_prolog=statements)
def __init__(self, rest): super(DimensionService, self).__init__(rest) self.hierarchies = HierarchyService(rest) self.subsets = SubsetService(rest)