Returns a dictionary mapping peptides to protein group leading proteins.

    :param peptides: a set of peptide sequences
    :param fastaPath: FASTA file path
    :param importAttributes: dict, can be used to override default parameters
        passed to the function maspy.proteindb.importProteinDatabase().
        Default attribtues are:
        {'cleavageRule': '[KR]', 'removeNtermM': True, 'ignoreIsoleucine': True,
         forceId': True, 'headerParser': PROTEINDB.fastaParserSpectraClusterPy}
    :param ignoreUnmapped: bool, if True ignores peptides that cannot be mapped
        to any protein present in the FASTA file

    :returns: dict, {peptide: set([groupLeaders1, ...])}
        where groupLeaders is a string joining all leading proteins of a group
        with a ";", for example {'peptide': {"protein1;proetin2;protein3"}}

def the_magic_mapping_function(peptides, fastaPath, importAttributes=None,
        ignoreUnmapped=True):
    """Returns a dictionary mapping peptides to protein group leading proteins.

    :param peptides: a set of peptide sequences
    :param fastaPath: FASTA file path
    :param importAttributes: dict, can be used to override default parameters
        passed to the function maspy.proteindb.importProteinDatabase().
        Default attribtues are:
        {'cleavageRule': '[KR]', 'removeNtermM': True, 'ignoreIsoleucine': True,
         forceId': True, 'headerParser': PROTEINDB.fastaParserSpectraClusterPy}
    :param ignoreUnmapped: bool, if True ignores peptides that cannot be mapped
        to any protein present in the FASTA file

    :returns: dict, {peptide: set([groupLeaders1, ...])}
        where groupLeaders is a string joining all leading proteins of a group
        with a ";", for example {'peptide': {"protein1;proetin2;protein3"}}
    """

    missedCleavage = max([p.count('K') + p.count('R') for p in peptides]) - 1
    minLength = min([len(p) for p in peptides])
    maxLength = max([len(p) for p in peptides])
    defaultAttributes = {
        'cleavageRule': '[KR]', 'minLength': minLength, 'maxLength': maxLength,
        'removeNtermM': True,  'ignoreIsoleucine': True,
        'missedCleavage': missedCleavage, 'forceId': True,
        'headerParser': PROTEINDB.fastaParserSpectraClusterPy,
    }
    if importAttributes is not None:
        defaultAttributes.update(importAttributes)

    proteindb = PROTEINDB.importProteinDatabase(fastaPath, **defaultAttributes)

    #This could be automated by adding a function to the inference module
    proteinToPeptides = ddict(set)
    for peptide in peptides:
        #ignore any peptide that's not mapped if "ignoreUnmapped" is True
        try:
            peptideDbEntry = proteindb.peptides[peptide]
        except KeyError as exception:
            if ignoreUnmapped:
                continue
            else:
                exceptionText = 'No protein mappings for peptide "'+peptide+'"'
                raise KeyError(exceptionText)

        for protein in peptideDbEntry.proteins:
            proteinToPeptides[protein].add(peptide)

    #Generate the ProteinInference instance
    inference = INFERENCE.mappingBasedGrouping(proteinToPeptides)

    peptideGroupMapping = dict()
    for peptide in peptides:
        groupLeaders = set()
        for proteinId in inference.pepToProts[peptide]:
            for proteinGroup in inference.getGroups(proteinId):
                groupLeaders.add(';'.join(sorted(proteinGroup.leading)))
        peptideGroupMapping[peptide] = groupLeaders

    return peptideGroupMapping