def _compile_column_metadata(row, keys, number):
    """
    Compile column metadata from one excel row ("9 part data")
    :param list row: Row of cells
    :param list keys: Variable header keys
    :return dict: Column metadata
    """
    # Store the variable keys by index in a dictionary
    _column = {}
    _interpretation = {}
    _calibration = {}
    _physical = {}

    # Use the header keys to place the column data in the dictionary
    if keys:
        for idx, key in enumerate(keys):
            _key_low = key.lower()

            # Special case: Calibration data
            if re.match(re_calibration, _key_low):
                m = re.match(re_calibration, _key_low)
                if m:
                    _key = m.group(1)
                    _calibration[_key] = row[idx].value

            # Special case: PhysicalSample data
            elif re.match(re_physical, _key_low):
                m = re.match(re_physical, _key_low)
                if m:
                    _key = m.group(1)
                    _physical[_key] = row[idx].value

            # Special case: Interpretation data
            elif re.match(re_interpretation, _key_low):
                # Put interpretation data in a tmp dictionary that we'll sort later.
                _interpretation[_key_low] = row[idx].value

            else:
                try:
                    val = row[idx].value
                except Exception:
                    logger_excel.info("compile_column_metadata: Couldn't get value from row cell")
                    val = "n/a"
                try:
                    if key == "variableName":
                        val = _rm_units_from_var_name_single(row[idx].value)
                except Exception:
                    # when a variableName fails to split, keep the name as-is and move on.
                    pass
                _column[key] = val
        _column["number"] = number

        if _calibration:
            _column["calibration"] = _calibration
        # Only allow physicalSample on measured variableTypes. duh.
        if _physical and _column["variableType"] == "measured":
            _column["physicalSample"] = _physical
        if _interpretation:
            _interpretation_data = _compile_interpretation(_interpretation)
            _column["interpretation"] = _interpretation_data

    # If there are not keys, that means it's a header-less metadata section.
    else:
        # Assume we only have one cell, because we have no keys to know what data is here.
        try:
            val = row[0].value.lower()
        except AttributeError:
            val = row[0].value
        except Exception:
            logger_excel.info("compile_column_metadata: Couldn't get value from row cell")
            val = "n/a"
        val = _rm_units_from_var_name_single(val)
        _column["variableName"] = val
        _column["number"] = number

    # Add this column to the overall metadata, but skip if there's no data present
    _column = {k: v for k, v in _column.items() if v}

    return _column
Compile column metadata from one excel row ("9 part data")
    :param list row: Row of cells
    :param list keys: Variable header keys
    :return dict: Column metadata