Returns FASTA entries for subject sequences from BLAST hits

    Stores B6/M8 entries with E-Values below the e_value cutoff. Then iterates
    through the FASTA file and if an entry matches the subject of an B6/M8
    entry, it's sequence is extracted and returned as a FASTA entry
    plus the E-Value.

    Args:
        fasta_handle (file): FASTA file handle, can technically
            be any iterable that returns FASTA "lines"

        b6_handle (file): B6/M8 file handle, can technically
            be any iterable that returns B6/M8 "lines"

        e_value (float): Max E-Value of entry to return

        *args: Variable length argument list for b6_iter

        **kwargs: Arbitrary keyword arguments for b6_iter

    Yields:
        FastaEntry: class containing all FASTA data

    Example:
        Note: These doctests will not pass, examples are only in doctest
        format as per convention. bio_utils uses pytests for testing.

        >>> fasta_handle = open('test.fasta')
        >>> b6_handle = open('test.b6')
        >>> for entry in subject_sequence_retriever(fasta_handle,
        ...                                       b6_handle, 1e5)
        ...     print(entry.sequence)  # Print aligned subject sequence

def subject_sequence_retriever(fasta_handle, b6_handle, e_value,
                               *args, **kwargs):
    """Returns FASTA entries for subject sequences from BLAST hits

    Stores B6/M8 entries with E-Values below the e_value cutoff. Then iterates
    through the FASTA file and if an entry matches the subject of an B6/M8
    entry, it's sequence is extracted and returned as a FASTA entry
    plus the E-Value.

    Args:
        fasta_handle (file): FASTA file handle, can technically
            be any iterable that returns FASTA "lines"

        b6_handle (file): B6/M8 file handle, can technically
            be any iterable that returns B6/M8 "lines"

        e_value (float): Max E-Value of entry to return

        *args: Variable length argument list for b6_iter

        **kwargs: Arbitrary keyword arguments for b6_iter

    Yields:
        FastaEntry: class containing all FASTA data

    Example:
        Note: These doctests will not pass, examples are only in doctest
        format as per convention. bio_utils uses pytests for testing.

        >>> fasta_handle = open('test.fasta')
        >>> b6_handle = open('test.b6')
        >>> for entry in subject_sequence_retriever(fasta_handle,
        ...                                       b6_handle, 1e5)
        ...     print(entry.sequence)  # Print aligned subject sequence
    """

    filtered_b6 = defaultdict(list)
    for entry in b6_evalue_filter(b6_handle, e_value, *args, **kwargs):
        filtered_b6[entry.subject].append(
            (entry.subject_start, entry.subject_end, entry._evalue_str))
    for fastaEntry in fasta_iter(fasta_handle):
        if fastaEntry.id in filtered_b6:
            for alignment in filtered_b6[fastaEntry.id]:
                start = alignment[0] - 1
                end = alignment[1] - 1

                # Get subject sequence
                if start < end:
                    subject_sequence = fastaEntry.sequence[start:end]
                elif start > end:
                    subject_sequence = fastaEntry.sequence[end:start][::-1]
                else:
                    subject_sequence = fastaEntry.sequence[start]
                fastaEntry.sequence = subject_sequence

                # Add E-value to FASTA/Q header
                if fastaEntry.description == '':
                    fastaEntry.description = 'E-value: '
                else:
                    fastaEntry.description += ' E-value: '
                fastaEntry.description += alignment[2]

                yield fastaEntry