Generates a :class:`ProteinDatabase` by in silico digestion of proteins
    from a fasta file.

    :param filePath: File path
    :param proteindb: optional an existing :class:`ProteinDatabase` can be
        specified, otherwise a new instance is generated and returned
    :param decoyTag: If a fasta file contains decoy protein entries, they should
        be specified with a sequence tag
    :param contaminationTag: If a fasta file contains contamination protein
        entries, they should be specified with a sequence tag
    :param headerParser: optional a headerParser can be specified
        #TODO: describe how a parser looks like
    :param forceId: bool, if True and no id can be extracted from the fasta
        header the whole header sequence is used as a protein id instead of
        raising an exception.
    :param cleavageRule: cleavage rule expressed in a regular expression, see
        :attr:`maspy.constants.expasy_rules`
    :param missedCleavage: number of allowed missed cleavage sites
    :param removeNtermM: bool, True to consider also peptides with the
        N-terminal Methionine of the protein removed
    :param minLength: int, only yield peptides with length >= minLength
    :param maxLength: int, only yield peptides with length <= maxLength
    :param ignoreIsoleucine: bool, if True treat Isoleucine and Leucine in
        peptide sequences as indistinguishable

    See also :func:`maspy.peptidemethods.digestInSilico`

def importProteinDatabase(filePath, proteindb=None, decoyTag='[decoy]',
        contaminationTag='[cont]', headerParser=None, forceId=False,
        cleavageRule='[KR]', minLength=5, maxLength=40, missedCleavage=2,
        ignoreIsoleucine=False, removeNtermM=True):
    """Generates a :class:`ProteinDatabase` by in silico digestion of proteins
    from a fasta file.

    :param filePath: File path
    :param proteindb: optional an existing :class:`ProteinDatabase` can be
        specified, otherwise a new instance is generated and returned
    :param decoyTag: If a fasta file contains decoy protein entries, they should
        be specified with a sequence tag
    :param contaminationTag: If a fasta file contains contamination protein
        entries, they should be specified with a sequence tag
    :param headerParser: optional a headerParser can be specified
        #TODO: describe how a parser looks like
    :param forceId: bool, if True and no id can be extracted from the fasta
        header the whole header sequence is used as a protein id instead of
        raising an exception.
    :param cleavageRule: cleavage rule expressed in a regular expression, see
        :attr:`maspy.constants.expasy_rules`
    :param missedCleavage: number of allowed missed cleavage sites
    :param removeNtermM: bool, True to consider also peptides with the
        N-terminal Methionine of the protein removed
    :param minLength: int, only yield peptides with length >= minLength
    :param maxLength: int, only yield peptides with length <= maxLength
    :param ignoreIsoleucine: bool, if True treat Isoleucine and Leucine in
        peptide sequences as indistinguishable

    See also :func:`maspy.peptidemethods.digestInSilico`
    """
    proteindb = ProteinDatabase() if proteindb is None else proteindb
    fastaRead = _readFastaFile(filePath)

    for header, sequence in fastaRead:
        proteinTags = list()
        if header.startswith(decoyTag):
            isDecoy = True
            header = header.replace(decoyTag, '')
            proteinTags.append(decoyTag)
        else:
            isDecoy = False

        if header.startswith(contaminationTag):
            isCont = True
            header = header.replace(contaminationTag, '')
            proteinTags.append(contaminationTag)
        else:
            isCont = False

        headerInfo = _extractFastaHeader(header, headerParser, forceId)
        proteinId = ''.join(itertools.chain(proteinTags, [headerInfo['id']]))
        if 'name' in headerInfo:
            proteinName = ''.join(itertools.chain(proteinTags,
                                                  [headerInfo['name']]
                                                  )
                                  )
        else:
            proteinName = proteinId

        if proteinId not in proteindb.proteins:
            protein = ProteinSequence(proteinId, sequence)
            protein.name = proteinName
            protein.fastaHeader = header
            protein.fastaInfo = headerInfo
            proteindb.proteins[protein.id] = protein

        #Perform the insilico digestion
        _digestion = maspy.peptidemethods.digestInSilico(sequence, cleavageRule,
                                                         missedCleavage,
                                                         removeNtermM,
                                                         minLength, maxLength
                                                         )

        #Add peptides to the protein database
        for unmodPeptide, info in _digestion:
            if ignoreIsoleucine:
                unmodPeptideNoIsoleucine = unmodPeptide.replace('I', 'L')
                if unmodPeptideNoIsoleucine in proteindb.peptides:
                    currPeptide = proteindb.peptides[unmodPeptideNoIsoleucine]
                else:
                    currPeptide = PeptideSequence(unmodPeptideNoIsoleucine,
                                                  mc=info['missedCleavage']
                                                  )
                    proteindb.peptides[unmodPeptideNoIsoleucine] = currPeptide

                if unmodPeptide not in proteindb.peptides:
                    proteindb.peptides[unmodPeptide] = currPeptide
            else:
                if unmodPeptide in proteindb.peptides:
                    currPeptide = proteindb.peptides[unmodPeptide]
                else:
                    currPeptide = PeptideSequence(unmodPeptide,
                                                  mc=info['missedCleavage']
                                                  )
                    proteindb.peptides[unmodPeptide] = currPeptide

            if proteinId not in currPeptide.proteins:
                currPeptide.proteins.add(proteinId)
                #TODO: change that a peptide can appear multiple times in a
                #  protein sequence.
                currPeptide.proteinPositions[proteinId] = (info['startPos'],
                                                           info['endPos']
                                                           )

    #Add peptide entries to the protein entries, define wheter a peptide can be
    #uniquely assigend to a single protein (.isUnique = True).
    for peptide, peptideEntry in viewitems(proteindb.peptides):
        numProteinMatches = len(peptideEntry.proteins)
        if numProteinMatches == 1:
            peptideEntry.isUnique = True
        elif numProteinMatches > 1:
            peptideEntry.isUnique = False
        else:
            raise Exception('No protein matches in proteindb for peptide' +
                            'sequence: ' + peptide)

        for proteinId in peptideEntry.proteins:
            if peptideEntry.isUnique:
                proteindb.proteins[proteinId].uniquePeptides.add(peptide)
            else:
                proteindb.proteins[proteinId].sharedPeptides.add(peptide)

    #Check protein entries if the digestions generated at least one peptide that
    #is uniquely assigned to the protein (.isUnique = True)
    for proteinEntry in viewvalues(proteindb.proteins):
        if len(proteinEntry.uniquePeptides) > 0:
            proteinEntry.isUnique = True
        else:
            proteinEntry.isUnique = False
    #Note: TODO, altough isoleucin is ignored, the protein entry should only
    #show the actually present ILE / LEU occurence, not any possibilities
    return proteindb