Translates each coding variant in a collection to one or more
    Translation objects, which are then aggregated into equivalent
    ProteinSequence objects.

    Parameters
    ----------
    variant_and_overlapping_reads_generator : generator
        Yields sequence of varcode.Variant objects paired with sequences
        of AlleleRead objects that support that variant.

    transcript_id_whitelist : set, optional
        If given, expected to be a set of transcript IDs which we should use
        for determining the reading frame around a variant. If omitted, then
        try to use all overlapping reference transcripts.

    protein_sequence_length : int
        Try to translate protein sequences of this length, though sometimes
        we'll have to return something shorter (depending on the RNAseq data,
        and presence of stop codons).

    min_alt_rna_reads : int
        Drop variant sequences at loci with fewer than this number of reads
        supporting the alt allele.

    min_variant_sequence_coverage : int
        Trim variant sequences to positions supported by at least this number
        of RNA reads.

    min_transcript_prefix_length : int
        Minimum number of bases we need to try matching between the reference
        context and variant sequence.

    max_transcript_mismatches : int
        Don't try to determine the reading frame for a transcript if more
        than this number of bases differ.

    include_mismatches_after_variant : bool
        Include mismatches after the variant locus in the count compared
        against max_transcript_mismatches.

    max_protein_sequences_per_variant : int
        Number of protein sequences to return for each ProteinSequence

    variant_cdna_sequence_assembly : bool
        If True, then assemble variant cDNA sequences based on overlap of
        RNA reads. If False, then variant cDNA sequences must be fully spanned
        and contained within RNA reads.

    Yields pairs of a Variant and a list of ProteinSequence objects

def reads_generator_to_protein_sequences_generator(
        variant_and_overlapping_reads_generator,
        transcript_id_whitelist=None,
        protein_sequence_length=PROTEIN_SEQUENCE_LENGTH,
        min_alt_rna_reads=MIN_ALT_RNA_READS,
        min_variant_sequence_coverage=MIN_VARIANT_SEQUENCE_COVERAGE,
        min_transcript_prefix_length=MIN_TRANSCRIPT_PREFIX_LENGTH,
        max_transcript_mismatches=MAX_REFERENCE_TRANSCRIPT_MISMATCHES,
        include_mismatches_after_variant=INCLUDE_MISMATCHES_AFTER_VARIANT,
        max_protein_sequences_per_variant=MAX_PROTEIN_SEQUENCES_PER_VARIANT,
        variant_sequence_assembly=VARIANT_SEQUENCE_ASSEMBLY):
    """"
    Translates each coding variant in a collection to one or more
    Translation objects, which are then aggregated into equivalent
    ProteinSequence objects.

    Parameters
    ----------
    variant_and_overlapping_reads_generator : generator
        Yields sequence of varcode.Variant objects paired with sequences
        of AlleleRead objects that support that variant.

    transcript_id_whitelist : set, optional
        If given, expected to be a set of transcript IDs which we should use
        for determining the reading frame around a variant. If omitted, then
        try to use all overlapping reference transcripts.

    protein_sequence_length : int
        Try to translate protein sequences of this length, though sometimes
        we'll have to return something shorter (depending on the RNAseq data,
        and presence of stop codons).

    min_alt_rna_reads : int
        Drop variant sequences at loci with fewer than this number of reads
        supporting the alt allele.

    min_variant_sequence_coverage : int
        Trim variant sequences to positions supported by at least this number
        of RNA reads.

    min_transcript_prefix_length : int
        Minimum number of bases we need to try matching between the reference
        context and variant sequence.

    max_transcript_mismatches : int
        Don't try to determine the reading frame for a transcript if more
        than this number of bases differ.

    include_mismatches_after_variant : bool
        Include mismatches after the variant locus in the count compared
        against max_transcript_mismatches.

    max_protein_sequences_per_variant : int
        Number of protein sequences to return for each ProteinSequence

    variant_cdna_sequence_assembly : bool
        If True, then assemble variant cDNA sequences based on overlap of
        RNA reads. If False, then variant cDNA sequences must be fully spanned
        and contained within RNA reads.

    Yields pairs of a Variant and a list of ProteinSequence objects
    """

    for (variant, overlapping_reads) in variant_and_overlapping_reads_generator:
        overlapping_transcript_ids = [
            t.id
            for t in variant.transcripts
            if t.is_protein_coding
        ]
        _, ref, alt = trim_variant(variant)
        overlapping_reads = list(overlapping_reads)
        reads_grouped_by_allele = group_reads_by_allele(overlapping_reads)

        ref_reads = reads_grouped_by_allele.get(ref, [])
        alt_reads = reads_grouped_by_allele.get(alt, [])

        translations = translate_variant_reads(
            variant=variant,
            variant_reads=alt_reads,
            transcript_id_whitelist=transcript_id_whitelist,
            protein_sequence_length=protein_sequence_length,
            min_alt_rna_reads=min_alt_rna_reads,
            min_variant_sequence_coverage=min_variant_sequence_coverage,
            min_transcript_prefix_length=min_transcript_prefix_length,
            max_transcript_mismatches=max_transcript_mismatches,
            include_mismatches_after_variant=include_mismatches_after_variant,
            variant_sequence_assembly=variant_sequence_assembly)

        protein_sequences = []
        for (key, equivalent_translations) in groupby(
                translations, key_fn=Translation.as_translation_key).items():

            # get the variant read names, transcript IDs and gene names for
            # protein sequence we're about to construct
            alt_reads_supporting_protein_sequence, group_transcript_ids, group_gene_names = \
                ProteinSequence._summarize_translations(equivalent_translations)

            logger.info(
                "%s: %s alt reads supporting protein sequence (gene names = %s)",
                key,
                len(alt_reads_supporting_protein_sequence),
                group_gene_names)

            protein_sequence = ProteinSequence.from_translation_key(
                translation_key=key,
                translations=equivalent_translations,
                overlapping_reads=overlapping_reads,
                alt_reads=alt_reads,
                ref_reads=ref_reads,
                alt_reads_supporting_protein_sequence=alt_reads_supporting_protein_sequence,
                transcripts_supporting_protein_sequence=group_transcript_ids,
                transcripts_overlapping_variant=overlapping_transcript_ids,
                gene=list(group_gene_names))
            logger.info("%s: protein sequence = %s" % (key, protein_sequence.amino_acids))
            protein_sequences.append(protein_sequence)

        # sort protein sequences before returning the top results
        protein_sequences = sort_protein_sequences(protein_sequences)

        yield variant, protein_sequences[:max_protein_sequences_per_variant]