Skip to content

Commit

Permalink
Extended error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
peterneher committed Mar 11, 2019
1 parent 815209d commit 5633156
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 10 deletions.
25 changes: 17 additions & 8 deletions cmdint/CmdInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import telegram
from pathlib import Path
from shutil import which
from cmdint.Utils import ThreadWithReturn, CmdLog
from cmdint.Utils import *


class CmdInterface:
Expand All @@ -35,8 +35,8 @@ class CmdInterface:
__autocommit_mainfile_repo: bool = False
__autocommit_mainfile_repo_done: bool = False
__immediate_return_on_run_not_necessary: bool = True
__exit_on_error: bool = True
__throw_on_error: bool = False
__exit_on_error: bool = False
__throw_on_error: bool = True
__installer_replacements: list = list()
__installer_command_suffix: str = '.sh'
__print_messages: bool = True
Expand Down Expand Up @@ -97,13 +97,13 @@ def set_print_messages(do_print: bool):

@staticmethod
def set_exit_on_error(do_exit: bool):
""" if True, CmdInterface calls exit() if an error is encountered. Default is True.
""" if True, CmdInterface calls exit() if an error is encountered. Default is False.
"""
CmdInterface.__exit_on_error = do_exit

@staticmethod
def set_throw_on_error(do_throw: bool):
""" if True, CmdInterface throws exception if an error is encountered. Default is False.
""" if True, CmdInterface throws exception if an error is encountered. Default is True.
"""
CmdInterface.__throw_on_error = do_throw

Expand Down Expand Up @@ -560,9 +560,12 @@ def __cmd_to_log(self, run_string: str, version_arg: str = None, silent: bool =
Run command line tool and store output in log.
"""
if silent:
retval = subprocess.call(run_string, shell=True, stdout=open(os.devnull, 'wb'))
retval = subprocess.call(run_string,
shell=True,
stdout=open(os.devnull, 'wb'),
stderr=open(os.devnull, 'wb'))
if retval != 0:
raise Exception('Command line subprocess return value is ' + str(retval))
raise OSError(retval, 'Command line subprocess return value is ' + str(retval))
return

# print version argument if using MITK cmd app or if version arg is specified explicitely
Expand Down Expand Up @@ -652,7 +655,7 @@ def __cmd_to_log(self, run_string: str, version_arg: str = None, silent: bool =
self.update_log()

if proc.returncode != 0 and not self.__ignore_cmd_retval:
raise Exception('Command line subprocess return value is ' + str(proc.returncode))
raise OSError(proc.returncode, 'Command line subprocess return value is ' + str(proc.returncode))

def update_log(self):
"""
Expand Down Expand Up @@ -748,6 +751,7 @@ def anonymize_log(out_log_name: str = None,
f_out.close()
except Exception as err:
print('Exception: ' + str(err))
print(err.args)

try:
data = list()
Expand All @@ -768,6 +772,7 @@ def anonymize_log(out_log_name: str = None,
json.dump(data, f, indent=2, sort_keys=False)
except Exception as err:
print('Exception: ' + str(err))
print(err.args)

for file in files_to_clear:
if os.path.isfile(file):
Expand All @@ -783,6 +788,7 @@ def anonymize_log(out_log_name: str = None,
f_out.close()
except Exception as err:
print('Exception: ' + str(err))
print(err.args)

for file in files_to_delete:
if os.path.isfile(file):
Expand All @@ -791,6 +797,7 @@ def anonymize_log(out_log_name: str = None,
os.remove(file)
except Exception as err:
print('Exception: ' + str(err))
print(err.args)

def run(self, version_arg: str = None,
pre_command: str = None,
Expand Down Expand Up @@ -888,6 +895,7 @@ def run(self, version_arg: str = None,
self.log_message('Something went wrong! Expected output files are missing: ' + str(missing_output))
self.__log['command']['output']['missing'] = missing_output
return_code = -1
exception = MissingOutputError(missing_output)
else:
# everything went as expected
self.__log['command']['output']['found'] = CmdInterface.get_file_hashes(check_output)
Expand All @@ -902,6 +910,7 @@ def run(self, version_arg: str = None,

elif not run_possible:
self.log_message('Skipping execution. Input files missing: ' + str(missing_inputs))
exception = MissingInputError(missing_inputs)

# end logging
self.__log_end(start_time)
Expand Down
10 changes: 10 additions & 0 deletions cmdint/Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ def next(self):
sys.stdout.flush()


class MissingInputError(Exception):
def __init__(self, message):
Exception.__init__(self, message)


class MissingOutputError(Exception):
def __init__(self, message):
Exception.__init__(self, message)


class ThreadWithReturn(threading.Thread):
"""
Helper class to run python functions in a separate thread and return it's output.
Expand Down
64 changes: 62 additions & 2 deletions test/cmdint_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,29 @@
import os
from pathlib import Path
from cmdint import CmdInterface
from cmdint.Utils import *


def nest():
print('TOPLEVEL NEST')
runner = CmdInterface(dummy_func)
runner.run()


def dummy_func():
print('dummy')


def dummy_exception():
raise Exception('DUMMY ERROR')


class CmdInterfaceTests(unittest.TestCase):

def setUp(self):
CmdInterface.set_throw_on_error(True)
CmdInterface.set_exit_on_error(False)

def test1(self):
with self.assertRaises(OSError):
CmdInterface('bla')
Expand All @@ -30,8 +45,53 @@ def test4(self):
self.assertTrue(os.path.isfile('CmdInterface.json'))
os.remove('CmdInterface.json')

def tearDown(self):
pass
def test5(self):
with self.assertRaises(OSError):
runner = CmdInterface('cp')
runner.run(silent=True)
self.assertTrue(not os.path.isfile('CmdInterface.json'))

def test6(self):
with self.assertRaises(Exception):
runner = CmdInterface(dummy_exception)
runner.run(silent=True)
self.assertTrue(not os.path.isfile('CmdInterface.json'))

def test7(self):
CmdInterface.set_static_logfile('CmdInterface.json', delete_existing=True)
CmdInterface.set_throw_on_error(False)
CmdInterface.set_exit_on_error(True)
with self.assertRaises(SystemExit):
runner = CmdInterface(dummy_exception)
runner.run(silent=False)
self.assertTrue(os.path.isfile('CmdInterface.json'))
os.remove('CmdInterface.json')

def test8(self):
with self.assertRaises(MissingInputError):
runner = CmdInterface('cp')
runner.add_arg(arg='NotExistingFile.txt', check_input=True)
runner.add_arg(arg='NotExistingFile.txt')
runner.run(silent=True)
self.assertTrue(not os.path.isfile('CmdInterface.json'))

def test9(self):
print(__file__)
with self.assertRaises(MissingOutputError):
runner = CmdInterface('echo')
runner.add_arg(arg='TEST', check_output=True)
runner.run(silent=True)
self.assertTrue(not os.path.isfile('CmdInterface.json'))

def test10(self):
print(__file__)
CmdInterface.set_static_logfile('/home/neher/cmdint/test/CmdInterface.json', delete_existing=True)
runner = CmdInterface(nest)
runner.run(silent=False)
self.assertTrue(os.path.isfile('/home/neher/cmdint/test/CmdInterface.json'))
os.remove('CmdInterface.json')

# TODO: check logfile contents


if __name__ == '__main__':
Expand Down

0 comments on commit 5633156

Please sign in to comment.