sct.log.info('\nCommand(s):') for args in list_args: sct.log.info(' ' + function_to_test + ' ' + args) sct.log.info('Dataset: ' + path_data) sct.log.info('Test integrity: ' + str(test_integrity)) # test function try: # retrieve subjects list list_subj = get_list_subj(path_data, data_specifications=data_specifications, fname_database=fname_database) # during testing, redirect to standard output to avoid stacking error messages in the general log if create_log: # handle_log.pause() sct.remove_handler(file_handler) # run function sct.log.debug("enter test fct") tests_ret = run_function(function_to_test, path_data, list_subj, list_args=list_args, nb_cpu=jobs, verbose=1, test_integrity=test_integrity) sct.log.debug("exit test fct") results = tests_ret['results'] compute_time = tests_ret['compute_time'] # after testing, redirect to log file if create_log: sct.log.addHandler(file_handler)
def test(path_data='', parameters=''): verbose = 0 dice_threshold = 0.9 add_path_for_template = False # if absolute path or no path to template is provided, then path to data should not be added. # initializations dice_template2anat = float('NaN') dice_anat2template = float('NaN') output = '' if not parameters: parameters = '-i t2/t2.nii.gz -l t2/labels.nii.gz -s t2/t2_seg.nii.gz ' \ '-param step=1,type=seg,algo=centermassrot,metric=MeanSquares:step=2,type=seg,algo=bsplinesyn,iter=5,metric=MeanSquares ' \ '-t template/ -r 0' add_path_for_template = True # in this case, path to data should be added parser = sct_register_to_template.get_parser() dict_param = parser.parse(parameters.split(), check_file_exist=False) if add_path_for_template: dict_param_with_path = parser.add_path_to_file(deepcopy(dict_param), path_data, input_file=True) else: dict_param_with_path = parser.add_path_to_file(deepcopy(dict_param), path_data, input_file=True, do_not_add_path=['-t']) param_with_path = parser.dictionary_to_string(dict_param_with_path) # Check if input files exist if not (os.path.isfile(dict_param_with_path['-i']) and os.path.isfile(dict_param_with_path['-l']) and os.path.isfile(dict_param_with_path['-s'])): status = 200 output = 'ERROR: the file(s) provided to test function do not exist in folder: ' + path_data return status, output, DataFrame(data={ 'status': int(status), 'output': output }, index=[path_data]) # return status, output, DataFrame( # data={'status': status, 'output': output, # 'dice_template2anat': float('nan'), 'dice_anat2template': float('nan')}, # index=[path_data]) # if template is not specified, use default # if not os.path.isdir(dict_param_with_path['-t']): # status, path_sct = commands.getstatusoutput('echo $SCT_DIR') # dict_param_with_path['-t'] = path_sct + default_template # param_with_path = parser.dictionary_to_string(dict_param_with_path) # get contrast folder from -i option. # We suppose we can extract it as the first object when spliting with '/' delimiter. contrast_folder = '' input_filename = '' if dict_param['-i'][0] == '/': dict_param['-i'] = dict_param['-i'][1:] input_split = dict_param['-i'].split('/') if len(input_split) == 2: contrast_folder = input_split[0] + '/' input_filename = input_split[1] else: input_filename = input_split[0] if not contrast_folder: # if no contrast folder, send error. status = 201 output = 'ERROR: when extracting the contrast folder from input file in command line: ' + dict_param[ '-i'] + ' for ' + path_data return status, output, DataFrame(data={ 'status': int(status), 'output': output }, index=[path_data]) # return status, output, DataFrame( # data={'status': status, 'output': output, 'dice_template2anat': float('nan'), 'dice_anat2template': float('nan')}, index=[path_data]) # create output path # TODO: create function for that import time, random subject_folder = path_data.split('/') if subject_folder[-1] == '' and len(subject_folder) > 1: subject_folder = subject_folder[-2] else: subject_folder = subject_folder[-1] path_output = sct.slash_at_the_end( 'sct_register_to_template_' + subject_folder + '_' + time.strftime("%y%m%d%H%M%S") + '_' + str(random.randint(1, 1000000)), slash=1) param_with_path += ' -ofolder ' + path_output sct.create_folder(path_output) # log file # TODO: create function for that import sys fname_log = path_output + 'output.log' sct.pause_stream_logger() file_handler = sct.add_file_handler_to_logger(filename=fname_log, mode='w', log_format="%(message)s") # # stdout_log = file(fname_log, 'w') # redirect to log file # stdout_orig = sys.stdout # sys.stdout = stdout_log cmd = 'sct_register_to_template ' + param_with_path output += '\n====================================================================================================\n' + cmd + '\n====================================================================================================\n\n' # copy command time_start = time.time() try: status, o = sct.run(cmd, verbose) except: status, o = 1, 'ERROR: Function crashed!' output += o duration = time.time() - time_start # if command ran without error, test integrity if status == 0: # get filename_template_seg fname_template_seg = get_file_label( sct.slash_at_the_end(dict_param_with_path['-t'], 1) + 'template/', 'spinal cord', output='filewithpath') # apply transformation to binary mask: template --> anat sct.run( 'sct_apply_transfo -i ' + fname_template_seg + ' -d ' + dict_param_with_path['-s'] + ' -w ' + path_output + 'warp_template2anat.nii.gz' + ' -o ' + path_output + 'test_template2anat.nii.gz -x nn', verbose) # apply transformation to binary mask: anat --> template sct.run( 'sct_apply_transfo -i ' + dict_param_with_path['-s'] + ' -d ' + fname_template_seg + ' -w ' + path_output + 'warp_anat2template.nii.gz' + ' -o ' + path_output + 'test_anat2template.nii.gz -x nn', verbose) # compute dice coefficient between template segmentation warped into anat and segmentation from anat cmd = 'sct_dice_coefficient -i ' + dict_param_with_path[ '-s'] + ' -d ' + path_output + 'test_template2anat.nii.gz' status1, output1 = sct.run(cmd, verbose) # parse output and compare to acceptable threshold dice_template2anat = float( output1.split('3D Dice coefficient = ')[1].split('\n')[0]) if dice_template2anat < dice_threshold: status1 = 99 # compute dice coefficient between segmentation from anat warped into template and template segmentation # N.B. here we use -bmax because the FOV of the anat is smaller than the template cmd = 'sct_dice_coefficient -i ' + fname_template_seg + ' -d ' + path_output + 'test_anat2template.nii.gz -bmax 1' status2, output2 = sct.run(cmd, verbose) # parse output and compare to acceptable threshold dice_anat2template = float( output2.split('3D Dice coefficient = ')[1].split('\n')[0]) if dice_anat2template < dice_threshold: status2 = 99 # check if at least one integrity status was equal to 99 if status1 == 99 or status2 == 99: status = 99 # concatenate outputs output = output + output1 + output2 # transform results into Pandas structure results = DataFrame(data={ 'status': int(status), 'output': output, 'dice_template2anat': dice_template2anat, 'dice_anat2template': dice_anat2template, 'duration [s]': duration }, index=[path_data]) sct.log.info(output) sct.remove_handler(file_handler) sct.start_stream_logger() return status, output, results
def test_function(param_test): """ Parameters ---------- file_testing Returns ------- path_output str: path where to output testing data """ sct.log.debug("Starting test function") # load modules of function to test module_function_to_test = importlib.import_module(param_test.function_to_test) module_testing = importlib.import_module('test_' + param_test.function_to_test) # retrieve subject name subject_folder = os.path.basename(param_test.path_data) # build path_output variable path_testing = os.getcwd() if not param_test.path_output: param_test.path_output = sct.tmp_create(basename=(param_test.function_to_test + '_' + subject_folder), verbose=0) elif not os.path.isdir(param_test.path_output): os.makedirs(param_test.path_output) # get parser information parser = module_function_to_test.get_parser() if '-ofolder' in parser.options and '-ofolder' not in param_test.args: param_test.args += " -ofolder " + param_test.path_output dict_args = parser.parse(shlex.split(param_test.args), check_file_exist=False) # TODO: if file in list does not exist, raise exception and assign status=200 # add data path to each input argument dict_args_with_path = parser.add_path_to_file(copy.deepcopy(dict_args), param_test.path_data, input_file=True) # add data path to each output argument dict_args_with_path = parser.add_path_to_file(copy.deepcopy(dict_args_with_path), param_test.path_output, input_file=False, output_file=True) # save into class param_test.dict_args_with_path = dict_args_with_path param_test.args_with_path = parser.dictionary_to_string(dict_args_with_path) # open log file # Note: the statement below is not included in the if, because even if redirection does not occur, we want the file to be create otherwise write_to_log will fail if param_test.fname_log is None: param_test.fname_log = os.path.join(param_test.path_output, param_test.function_to_test + '.log') # redirect to log file if param_test.redirect_stdout: file_handler = sct.add_file_handler_to_logger(param_test.fname_log) sct.log.debug("logging to file") # initialize panda dataframe sct.log.debug("Init dataframe") param_test.results = DataFrame(index=[subject_folder], data={'status': 0, 'duration': 0, 'output': '', 'path_data': param_test.path_data, 'path_output': param_test.path_output}) # retrieve input file (will be used later for integrity testing) if '-i' in dict_args: # check if list in case of multiple input files if not isinstance(dict_args_with_path['-i'], list): list_file_to_check = [dict_args_with_path['-i']] # assign field file_input for integrity testing param_test.file_input = dict_args['-i'].split('/')[-1] # update index of dataframe by appending file name for more clarity param_test.results = param_test.results.rename({subject_folder: os.path.join(subject_folder, dict_args['-i'])}) else: list_file_to_check = dict_args_with_path['-i'] # TODO: assign field file_input for integrity testing for file_to_check in list_file_to_check: # file_input = file_to_check.split('/')[1] # Check if input files exist if not (os.path.isfile(file_to_check)): param_test.status = 200 param_test.output += '\nERROR: This input file does not exist: ' + file_to_check write_to_log_file(param_test.fname_log, param_test.output, 'w') return update_param(param_test) # retrieve ground truth (will be used later for integrity testing) if '-igt' in dict_args: param_test.fname_gt = dict_args_with_path['-igt'] # Check if ground truth files exist if not os.path.isfile(param_test.fname_gt): param_test.status = 201 param_test.output += '\nERROR: The following file used for ground truth does not exist: ' + param_test.fname_gt write_to_log_file(param_test.fname_log, param_test.output, 'w') return update_param(param_test) # run command cmd = param_test.function_to_test + param_test.args_with_path param_test.output += '\nWill run in %s:' % (os.path.join(path_testing, param_test.path_output)) param_test.output += '\n====================================================================================================\n' + cmd + '\n====================================================================================================\n\n' # copy command time_start = time.time() try: os.chdir(param_test.path_output) if not os.path.exists(param_test.path_output): # in case of relative path, we want a subfolder too os.makedirs(param_test.path_output) os.chdir(path_testing) param_test.status, o = sct.run(cmd, cwd=param_test.path_output, verbose=0) if param_test.status: raise Exception except Exception as err: param_test.status = 1 param_test.output += str(err) write_to_log_file(param_test.fname_log, param_test.output, 'w') return update_param(param_test) param_test.output += o param_test.results['duration'] = time.time() - time_start # test integrity if param_test.test_integrity: param_test.output += '\n\n====================================================================================================\n' + 'INTEGRITY TESTING' + '\n====================================================================================================\n\n' # copy command try: os.chdir(param_test.path_output) param_test = module_testing.test_integrity(param_test) os.chdir(path_testing) except Exception as err: os.chdir(path_testing) param_test.status = 2 param_test.output += str(err) write_to_log_file(param_test.fname_log, param_test.output, 'w') return update_param(param_test) # manage stdout if param_test.redirect_stdout: sct.remove_handler(file_handler) write_to_log_file(param_test.fname_log, param_test.output, mode='r+', prepend=True) return update_param(param_test)
# display command logger.info('\nCommand(s):') for args in list_args: logger.info(' ' + function_to_test + ' ' + args) logger.info('Dataset: ' + path_data) logger.info('Test integrity: ' + str(test_integrity)) # test function try: # retrieve subjects list list_subj = get_list_subj(path_data, data_specifications=data_specifications, fname_database=fname_database) # during testing, redirect to standard output to avoid stacking error messages in the general log if create_log: # handle_log.pause() sct.remove_handler(file_handler) # run function logger.debug("enter test fct") tests_ret = run_function(function_to_test, path_data, list_subj, list_args=list_args, nb_cpu=jobs, verbose=1, test_integrity=test_integrity) logger.debug("exit test fct") results = tests_ret['results'] compute_time = tests_ret['compute_time'] # after testing, redirect to log file if create_log: logger.addHandler(file_handler) # build results pd.set_option('display.max_rows', 500) pd.set_option('display.max_columns', 500) pd.set_option('display.max_colwidth', -1) # to avoid truncation of long string pd.set_option('display.width', 1000) # drop entries for visibility