From 4f4751532042d37a78020b55c71d3174af187a56 Mon Sep 17 00:00:00 2001 From: Peter Neher Date: Fri, 22 Mar 2019 13:51:24 +0100 Subject: [PATCH] Refactor silence mode and exceptions --- cmdint/CmdInterface.py | 111 +++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 43 deletions(-) diff --git a/cmdint/CmdInterface.py b/cmdint/CmdInterface.py index 648a48e..2e30ca5 100644 --- a/cmdint/CmdInterface.py +++ b/cmdint/CmdInterface.py @@ -71,13 +71,16 @@ def __init__(self, command, static_logfile: str = None): self.__py_function_return = None self.__nested = False + self.__no_new_log = False self.__ignore_cmd_retval = False + self.__silent = False if not self.__is_py_function: command = command.strip() if CmdInterface.__use_installer: command += CmdInterface.__installer_command_suffix if len(command) == 0 or which(command) is None: + print('Command not found: ' + command) raise OSError('Command not found: ' + command) if not self.__is_py_function and self.__no_key_options[0][:4] == 'Mitk': @@ -257,6 +260,7 @@ def add_repo_path(path: str, autocommit: bool = False): CmdInterface.__git_repos[path]['autocommit'] = autocommit CmdInterface.__check_repo(path) else: + print('"' + path + '" is not a directory') raise NotADirectoryError('"' + path + '" is not a directory') @staticmethod @@ -310,6 +314,8 @@ def remove_arg(self, key: str): self.__check_output.remove(self.__options[key]) del self.__options[key] else: + print('No argument with specified keyword found! Arguments without keyword cannot be removed. ' + 'Create a new instance of CmdInterface in this case.') raise ValueError('No argument with specified keyword found! Arguments without keyword cannot be removed. ' 'Create a new instance of CmdInterface in this case.') @@ -333,6 +339,7 @@ def add_arg(self, return if self.__is_py_function: if key is None: + print('Only arguments with keyword are allowed when executing python functions!') raise ValueError('Only arguments with keyword are allowed when executing python functions!') if check_input: @@ -471,17 +478,19 @@ def __log_start(self) -> datetime: self.__log['command']['time']['start'] = start_time.strftime("%Y-%m-%d %H:%M:%S") self.__log['command']['time']['utc_offset'] = time.localtime().tm_gmtoff self.log_message(start_time.strftime("%Y-%m-%d %H:%M:%S") + ' >> ' + self.__log['command']['name'] + ' START') - if CmdInterface.__send_start: + if CmdInterface.__send_start and not self.__silent: CmdInterface.send_telegram_message('START ' + self.__log['command']['name']) return start_time - def __log_end(self, start_time: datetime) -> datetime: + def __log_end(self, start_time: datetime, return_code: int) -> datetime: """ Log end time and duration of command execution: ['command']['time']['end'] ['command']['time']['duration'] Return end time. """ + + # set times end_time = datetime.now() self.__log['command']['time']['end'] = end_time.strftime("%Y-%m-%d %H:%M:%S") @@ -493,7 +502,22 @@ def __log_end(self, start_time: datetime) -> datetime: minutes, seconds = divmod(remainder, 60) duration_formatted = '%d:%02d:%02d' % (hours, minutes, seconds) self.__log['command']['time']['duration'] = duration_formatted + + # log end messages & return code self.log_message(end_time.strftime("%Y-%m-%d %H:%M:%S") + ' >> ' + self.__log['command']['name'] + ' END') + if (CmdInterface.__throw_on_error or CmdInterface.__exit_on_error) and return_code <= 0: + self.log_message('Exiting due to error: ' + self.__return_code_meanings[return_code]) + self.__log['command']['return_code'] = return_code + self.update_log() + + if not self.__silent: + if CmdInterface.__send_log: + CmdInterface.send_telegram_logfile( + message='END ' + self.__log['command']['name'] + '\n' + self.__return_code_meanings[return_code]) + elif CmdInterface.__send_end: + CmdInterface.send_telegram_message( + message='END ' + self.__log['command']['name'] + '\n' + self.__return_code_meanings[return_code]) + return end_time def log_message(self, message: str, via_telegram: bool = False): @@ -507,7 +531,7 @@ def log_message(self, message: str, via_telegram: bool = False): if via_telegram: CmdInterface.send_telegram_message(message) - def __pyfunction_to_log(self, silent: bool = False): + def __pyfunction_to_log(self): """ Run python function and store terminal output in log (['command']['text_output']). """ @@ -515,7 +539,7 @@ def __pyfunction_to_log(self, silent: bool = False): original_stderr = sys.stderr sys.stdout = sys.stderr = out_string = io.StringIO() - if silent: + if self.__silent: try: self.__no_key_options[0](*self.__no_key_options[1:], **self.__options) @@ -555,11 +579,11 @@ def __pyfunction_to_log(self, silent: bool = False): if exception is not None: raise exception - def __cmd_to_log(self, run_string: str, version_arg: str = None, silent: bool = False): + def __cmd_to_log(self, run_string: str, version_arg: str = None): """ Run command line tool and store output in log. """ - if silent: + if self.__silent: retval = subprocess.call(run_string, shell=True, stdout=open(os.devnull, 'wb'), @@ -661,7 +685,7 @@ def update_log(self): """ Replace last entry of the json logfile by log of current instance. """ - if CmdInterface.__logfile_name is None: + if CmdInterface.__logfile_name is None or self.__no_new_log: return self.__log['command']['return_code_meaning'] = self.__return_code_meanings[self.__log['command']['return_code']] self.__log['cmd_interface']['repositories'] = CmdInterface.__git_repos @@ -682,7 +706,7 @@ def append_log(self): """ Append log of current instance to the output json file. Creates new json if it does not exist. """ - if CmdInterface.__logfile_name is None: + if CmdInterface.__logfile_name is None or self.__no_new_log: return self.__log['command']['return_code_meaning'] = self.__return_code_meanings[self.__log['command']['return_code']] self.__log['cmd_interface']['repositories'] = CmdInterface.__git_repos @@ -830,9 +854,10 @@ def run(self, version_arg: str = None, # check if run has been called recoursively (CmdInterface inside of CmdInterface) self.__nested = False - user_silent = silent + self.__no_new_log = silent + self.__silent = silent if CmdInterface.__called: - silent = True + self.__no_new_log = True self.__nested = True CmdInterface.__called = True @@ -873,8 +898,7 @@ def run(self, version_arg: str = None, self.__log['command']['run_string'] = run_string start_time = self.__log_start() - if not silent: - self.append_log() + self.append_log() exception = None if run_necessary and run_possible: @@ -883,11 +907,10 @@ def run(self, version_arg: str = None, try: # run command if self.__is_py_function: - self.__pyfunction_to_log(silent=user_silent) # command is python function + self.__pyfunction_to_log() # command is python function else: self.__cmd_to_log(run_string=run_string, - version_arg=version_arg, - silent=user_silent) # command is external tool + version_arg=version_arg) # command is external tool # check if output was produced as expected missing_output = CmdInterface.check_exist(check_output) @@ -900,10 +923,33 @@ def run(self, version_arg: str = None, # everything went as expected self.__log['command']['output']['found'] = CmdInterface.get_file_hashes(check_output) return_code = 1 + except MissingOutputError as err: + return_code = -1 + exception = err + + exc_type, exc_obj, exc_tb = sys.exc_info() + fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] + self.log_message('Exception: ' + exc_type.__name__) + self.log_message('In file: ' + fname) + self.log_message('Line: ' + str(exc_tb.tb_lineno)) + except MissingInputError as err: + return_code = -2 + exception = err + + exc_type, exc_obj, exc_tb = sys.exc_info() + fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] + self.log_message('Exception: ' + exc_type.__name__) + self.log_message('In file: ' + fname) + self.log_message('Line: ' + str(exc_tb.tb_lineno)) except Exception as err: return_code = -3 exception = err - self.log_message('Exception: ' + str(err)) + + exc_type, exc_obj, exc_tb = sys.exc_info() + fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] + self.log_message('Exception: ' + exc_type.__name__) + self.log_message('In file: ' + fname) + self.log_message('Line: ' + str(exc_tb.tb_lineno)) elif not run_necessary: self.log_message('Skipping execution. All output files already present.') @@ -912,41 +958,20 @@ def run(self, version_arg: str = None, self.log_message('Skipping execution. Input files missing: ' + str(missing_inputs)) exception = MissingInputError(missing_inputs) - # end logging - self.__log_end(start_time) - if not self.__nested: CmdInterface.__called = False - if (CmdInterface.__throw_on_error or CmdInterface.__exit_on_error) and return_code <= 0: - self.log_message('Exiting due to error: ' + self.__return_code_meanings[return_code]) - self.__log['command']['return_code'] = return_code - if not silent: - self.update_log() - if CmdInterface.__send_log: - CmdInterface.send_telegram_logfile( - message='END ' + self.__log['command']['name'] + '\n' + self.__return_code_meanings[return_code]) - elif CmdInterface.__send_end: - CmdInterface.send_telegram_message( - message='END ' + self.__log['command']['name'] + '\n' + self.__return_code_meanings[return_code]) + # end logging + self.__log_end(start_time, return_code=return_code) + + self.__log = CmdLog() + if (CmdInterface.__throw_on_error or CmdInterface.__exit_on_error) and return_code <= 0: if CmdInterface.__throw_on_error or self.__nested: if exception is not None: raise exception else: raise Exception('Exiting due to error: ' + self.__return_code_meanings[return_code]) - if CmdInterface.__exit_on_error: + elif CmdInterface.__exit_on_error: exit() - self.__log['command']['return_code'] = return_code - if not silent: - self.update_log() - - if CmdInterface.__send_log: - CmdInterface.send_telegram_logfile( - message='END ' + self.__log['command']['name'] + '\n' + self.__return_code_meanings[return_code]) - elif CmdInterface.__send_end: - CmdInterface.send_telegram_message( - message='END ' + self.__log['command']['name'] + '\n' + self.__return_code_meanings[return_code]) - - self.__log = CmdLog() return return_code