def read_upload(up_file, data_model=None):
    """
    take a file that should be ready for upload
    using the data model, check that all required columns are full,
    and that all numeric data is in fact numeric.
    print out warnings for any validation problems
    return True if there were no problems, otherwise return False
    """
    print("-I- Running validation for your upload file")

    ## Read file
    f = open(up_file)
    lines = f.readlines()
    f.close()
    data = split_lines(lines)
    data_dicts = get_dicts(data)
    ## initialize
    invalid_data = {}
    missing_data = {}
    non_numeric = {}
    bad_vocab = {}
    bad_coords = {}
    invalid_col_names = {}
    missing_file_type = False
    ## make sure you have the data model
    if not data_model:
        data_model = get_data_model()
    reqd_file_types = ['er_locations']
    provided_file_types = set()
    if not data_model:
        return False, None
    ## Iterate through data
    # each dictionary is one tab delimited line in a csv file
    for dictionary in data_dicts:
        for k, v in list(dictionary.items()):
            if k == "file_type": # meta data
                provided_file_types.add(v)
                continue
            file_type = dictionary['file_type']
            # need to deal with pmag_criteria type file, too
            item_type = file_type.split('_')[1][:-1]
            if item_type == 'criteria':
                item_name = dictionary.get('criteria_definition')
            elif item_type == 'result':
                item_name = dictionary.get('pmag_result_name', None)
            elif item_type in ('specimen', 'sample', 'site', 'location'):
                item_name = dictionary.get('er_' + item_type + '_name', None)
            elif item_type == 'age':
                # get the lowest level er_*_name column that is filled in
                for dtype in ('specimen', 'sample', 'site', 'location'):
                    item_name = dictionary.get('er_' + dtype + '_name', None)
                    if item_name:
                        break
            elif item_type == 'measurement':
                exp_name = dictionary.get('magic_experiment_name')
                meas_num = dictionary.get('measurement_number')
                item_name = exp_name + '_' + str(meas_num)
            else:
                item_name = None

            if file_type not in list(data_model.keys()):
                continue
            specific_data_model = data_model[file_type]

            ## Function for building problems list
            def add_to_invalid_data(item_name, item_type, invalid_data,
                                    validation, problem_type):
                """
                correctly create or add to the dictionary of invalid values
                """
                if item_name:
                    if item_type not in invalid_data:
                        invalid_data[item_type] = {}
                    if item_name not in invalid_data[item_type]:
                        invalid_data[item_type][item_name] = {}
                    if problem_type not in invalid_data[item_type][item_name]:
                        invalid_data[item_type][item_name][problem_type] = []
                    invalid_data[item_type][item_name][problem_type].append(validation)

            ## Validate for each problem type

            # check if column header is in the data model
            invalid_col_name = validate_for_recognized_column(k, v, specific_data_model)
            if invalid_col_name:
                if item_type not in list(invalid_col_names.keys()):
                    invalid_col_names[item_type] = set()
                invalid_col_names[item_type].add(invalid_col_name)
                # skip to next item, as additional validations won't work
                # (key is not in the data model)

                ## new style
                add_to_invalid_data(item_name, item_type, invalid_data,
                                    invalid_col_name, 'invalid_col')
                # skip to next item, as additional validations won't work
                # (key is not in the data model)
                continue

            # make a list of missing, required data
            missing_item = validate_for_presence(k, v, specific_data_model)
            #print 'k, v', k, v
            if missing_item:
                if item_type not in list(missing_data.keys()):
                    missing_data[item_type] = set()
                missing_data[item_type].add(missing_item)
                if item_name:
                    # don't double count if a site is missing its parent location
                    if item_type == 'age' and missing_item == 'er_location_name':
                        pass
                    # ignore er_synthetic_name (data model is incorrect here)
                    if missing_item == 'er_synthetic_name':
                        pass
                    else:
                        add_to_invalid_data(item_name, item_type, invalid_data,
                                            missing_item, 'missing_data')

            # vocabulary problems
            vocab_problem = validate_for_controlled_vocab(k, v, specific_data_model)
            if vocab_problem:
                if item_type not in list(bad_vocab.keys()):
                    bad_vocab[item_type] = set()
                bad_vocab[item_type].add(vocab_problem)
                add_to_invalid_data(item_name, item_type, invalid_data,
                                    vocab_problem, 'vocab_problem')

            # illegal coordinates
            coord_problem = validate_for_coordinates(k, v, specific_data_model)
            if coord_problem:
                if item_type not in list(bad_coords.keys()):
                    bad_coords[item_type] = set()
                bad_coords[item_type].add(coord_problem)
                add_to_invalid_data(item_name, item_type, invalid_data,
                                    coord_problem, 'coordinates')

            # make a list of data that should be numeric, but aren't
            number_fail = validate_for_numericality(k, v, specific_data_model)
            if number_fail:
                if item_type not in list(non_numeric.keys()):
                    non_numeric[item_type] = set()
                non_numeric[item_type].add(number_fail)
                add_to_invalid_data(item_name, item_type, invalid_data,
                                    number_fail, 'number_fail')

    ## Print out all issues

    for file_type, invalid_names in list(invalid_col_names.items()):
        print("-W- In your {} file, you are using the following unrecognized columns: {}".format(file_type, ', '.join(invalid_names)))

    for file_type, wrong_cols in list(non_numeric.items()):
        print("-W- In your {} file, you must provide only valid numbers, in the following columns: {}".format(file_type, ', '.join(wrong_cols)))

    for file_type, empty_cols in list(missing_data.items()):
        print("-W- In your {} file, you are missing data in the following required columns: {}".format(file_type, ', '.join(empty_cols)))

    for file_type in reqd_file_types:
        if file_type not in provided_file_types:
            print("-W- You have not provided a(n) {} type file, which is required data".format(file_type))
            missing_file_type = True

    for file_type, vocab_types in list(bad_vocab.items()):
        print("-W- In your {} file, you are using an unrecognized value for these controlled vocabularies: {}".format(file_type, ', '.join(vocab_types)))

    for file_type, coords in list(bad_coords.items()):
        print("-W- In your {} file, you are using an illegal value for these columns: {}.  (Latitude must be between -90 and +90)".format(file_type, ', '.join(coords)))


    if any((invalid_col_names, non_numeric, missing_data, missing_file_type, bad_vocab, bad_coords)):
        return False, invalid_data
    else:
        print("-I- validation was successful")
        return True, None