def update(self, process: Process, **kwargs) -> Response: """ Update an existing Process on TM1 Server :param process: Instance of TM1py.Process class :return: Response """ url = format_url("/api/v1/Processes('{}')", process.name) # Adjust process body if TM1 version is lower than 11 due to change in Process Parameters structure # https://www.ibm.com/developerworks/community/forums/html/topic?id=9188d139-8905-4895-9229-eaaf0e7fa683 if int(self.version[0:2]) < 11: process.drop_parameter_types() response = self._rest.PATCH(url, process.body, **kwargs) return response
def get_all(self, skip_control_processes: bool = False, **kwargs) -> List[Process]: """ Get a processes from TM1 Server :param skip_control_processes: bool, True to exclude processes that begin with "}" or "{" :return: List, instances of the TM1py.Process """ model_process_filter = "&$filter=startswith(Name,'}') eq false and startswith(Name,'{') eq false" url = "/api/v1/Processes?$select=*,UIData,VariablesUIData," \ "DataSource/dataSourceNameForServer," \ "DataSource/dataSourceNameForClient," \ "DataSource/asciiDecimalSeparator," \ "DataSource/asciiDelimiterChar," \ "DataSource/asciiDelimiterType," \ "DataSource/asciiHeaderRecords," \ "DataSource/asciiQuoteCharacter," \ "DataSource/asciiThousandSeparator," \ "DataSource/view," \ "DataSource/query," \ "DataSource/userName," \ "DataSource/password," \ "DataSource/usesUnicode," \ "DataSource/subset{}".format(model_process_filter if skip_control_processes else "") response = self._rest.GET(url, **kwargs) response_as_dict = response.json() return [Process.from_dict(p) for p in response_as_dict['value']]
def load_bedrock_from_github(bedrock_process_name): """ Load bedrock from GitHub as TM1py.Process instance :param name_bedrock_process: :return: """ import requests url = 'https://raw.githubusercontent.com/MariusWirtz/bedrock/master/json/{}.json'.format(bedrock_process_name) process_as_json = requests.get(url).text return Process.from_json(process_as_json)
def evaluate_ti_expression(self, formula: str, **kwargs) -> str: """ This function is same functionality as hitting "Evaluate" within variable formula editor in TI Function creates temporary TI and then starts a debug session on that TI EnableTIDebugging=T must be present in .cfg file Only suited for Deb and one-off uses, don't incorporate into dataframe lambda function :param formula: a valid tm1 variable formula (no double quotes, no equals sign, semicolon optional) e.g. "8*2;", "CellGetN('c1', 'e1', 'e2);", "ATTRS('Region', 'France', 'Currency')" :returns: string result from formula """ # grab everything to right of "=" if present formula = formula[formula.find('=') + 1:] # make sure semicolon at end is present if not formula.strip().endswith(";"): formula += ";" prolog_list = ["sFunc = {}".format(formula), "sDebug='Stop';"] process_name = "".join(['}TM1py', str(uuid.uuid4())]) p = Process(name=process_name, prolog_procedure=Process.AUTO_GENERATED_STATEMENTS + '\r\n'.join(prolog_list)) syntax_errors = self.compile_process(p, **kwargs) if syntax_errors: raise ValueError(str(syntax_errors)) try: self.create(p, **kwargs) debug_id = self.debug_process(p.name, **kwargs)['ID'] break_point = ProcessDebugBreakpoint( breakpoint_id=1, breakpoint_type='ProcessDebugContextDataBreakpoint', enabled=True, hit_mode='BreakAlways', variable_name='sFunc') self.debug_add_breakpoint(debug_id=debug_id, break_point=break_point, **kwargs) self.debug_continue(debug_id, **kwargs) result = self.debug_get_variable_values(debug_id, **kwargs) self.debug_continue(debug_id, **kwargs) if not result: raise ValueError('unknown error: no formula result found') else: return result[-2]['Value'] except TM1pyRestException as e: raise e finally: self.delete(p.name, **kwargs)
def load_all_bedrocks_from_github(): """ Load all Bedrocks from GitHub as TM1py.Process instances :return: """ import requests # Connect to Bedrock github repo and load the names of all Bedrocks url = "https://api.github.com/repos/MariusWirtz/bedrock/contents/json?ref=master" raw_github_data = requests.get(url).json() all_bedrocks = [entry['name'] for entry in raw_github_data] # instantiate TM1py.Process instances from github-json content url_to_bedrock = 'https://raw.githubusercontent.com/MariusWirtz/bedrock/master/json/{}' return [Process.from_json(requests.get(url_to_bedrock.format(bedrock)).text) for bedrock in all_bedrocks]
def execute_process_with_return(self, process: Process, timeout: float = None, cancel_at_timeout: bool = False, **kwargs) -> Tuple[bool, str, str]: """Run unbound TI code directly. :param process: a TI Process Object :param timeout: Number of seconds that the client will wait to receive the first byte. :param cancel_at_timeout: Abort operation in TM1 when timeout is reached :param kwargs: dictionary of process parameters and values :return: success (boolean), status (String), error_log_file (String) """ url = "/api/v1/ExecuteProcessWithReturn?$expand=*" if kwargs: for parameter_name, parameter_value in kwargs.items(): process.remove_parameter(name=parameter_name) process.add_parameter(name=parameter_name, prompt=parameter_name, value=parameter_value) payload = json.loads("{\"Process\":" + process.body + "}") response = self._rest.POST(url=url, data=json.dumps(payload, ensure_ascii=False), timeout=timeout, cancel_at_timeout=cancel_at_timeout, **kwargs) execution_summary = response.json() success = execution_summary[ "ProcessExecuteStatusCode"] == "CompletedSuccessfully" status = execution_summary["ProcessExecuteStatusCode"] error_log_file = None if execution_summary[ "ErrorLogFile"] is None else execution_summary["ErrorLogFile"][ "Filename"] return success, status, error_log_file
def execute_ti_code(self, lines_prolog: Iterable[str], lines_epilog: Iterable[str] = None, **kwargs) -> Response: """ Execute lines of code on the TM1 Server :param lines_prolog: list - where each element is a valid statement of TI code. :param lines_epilog: list - where each element is a valid statement of TI code. """ process_name = "".join(['}TM1py', str(uuid.uuid4())]) p = Process(name=process_name, prolog_procedure=Process.AUTO_GENERATED_STATEMENTS + '\r\n'.join(lines_prolog), epilog_procedure=Process.AUTO_GENERATED_STATEMENTS + '\r\n'.join(lines_epilog) if lines_epilog else '') self.create(p, **kwargs) try: return self.execute(process_name, **kwargs) except TM1pyRestException as e: raise e finally: self.delete(process_name, **kwargs)
def get_all(self, **kwargs) -> List[Process]: """ Get a processes from TM1 Server :return: List, instances of the TM1py.Process """ url = "/api/v1/Processes?$select=*,UIData,VariablesUIData," \ "DataSource/dataSourceNameForServer," \ "DataSource/dataSourceNameForClient," \ "DataSource/asciiDecimalSeparator," \ "DataSource/asciiDelimiterChar," \ "DataSource/asciiDelimiterType," \ "DataSource/asciiHeaderRecords," \ "DataSource/asciiQuoteCharacter," \ "DataSource/asciiThousandSeparator," \ "DataSource/view," \ "DataSource/query," \ "DataSource/userName," \ "DataSource/password," \ "DataSource/usesUnicode," \ "DataSource/subset" response = self._rest.GET(url, **kwargs) response_as_dict = response.json() return [Process.from_dict(p) for p in response_as_dict['value']]
def get(self, name_process: str, **kwargs) -> Process: """ Get a process from TM1 Server :param name_process: :return: Instance of the TM1py.Process """ url = format_url( "/api/v1/Processes('{}')?$select=*,UIData,VariablesUIData," "DataSource/dataSourceNameForServer," "DataSource/dataSourceNameForClient," "DataSource/asciiDecimalSeparator," "DataSource/asciiDelimiterChar," "DataSource/asciiDelimiterType," "DataSource/asciiHeaderRecords," "DataSource/asciiQuoteCharacter," "DataSource/asciiThousandSeparator," "DataSource/view," "DataSource/query," "DataSource/userName," "DataSource/password," "DataSource/usesUnicode," "DataSource/subset", name_process) response = self._rest.GET(url, **kwargs) return Process.from_dict(response.json())
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}'" )