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)
Esempio n. 2
0
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
Esempio n. 3
0
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