<commit_before>import os
import subprocess
from Bio.Blast import NCBIXML
from Bio.Blast.Applications import NcbiblastnCommandline
from .fasta_io import write_sequences
import temporary


class Blast(object):
    """Hold Blast-related data and methods."""

    def __init__(self, sequence, blastdb=None, reference_fasta=None):
        """
        Blast object for `sequences`.

        Writes out sequences in `sequences` dict as fasta and aligns sequences against `blastdb`.

        >>> from test.helpers import roo_seq
        >>> with temporary.temp_dir() as tempdir:
        ...     reference_fasta = os.path.join(str(tempdir), 'reference.fasta')
        ...     write_sequences({'roo_fragment': roo_seq}, output_path=reference_fasta)
        ...     s = 'ATCGAGAGCGATAAATTATATTTAGGATTTTGTTATCTAAGGCGACAGCTCAAAAACATGTAATTTAAGTGCACACTACATGAGTCAGTCACTTGAGATCGTTCCCCGCCTCCTAAAAT'
        ...     sequence = {'test': s}
        ...     b = Blast(sequence=sequence, reference_fasta=reference_fasta)
        >>> len(b.blast_result[0].alignments) == 1
        True
        """
        self.sequence = sequence
        self.blastdb = blastdb
        self.reference_fasta = reference_fasta
        self.blast_result = self.run()

    def run(self):
        """Run blast command."""
        with temporary.temp_dir(make_cwd=True) as temp_dir:
            temp_dir = str(temp_dir)
            if not self.blastdb:
                self.blastdb = make_blastdb(self.reference_fasta, dir=temp_dir)
            input_path = os.path.abspath(os.path.join(temp_dir, 'blast.fa'))
            outfile = 'blast_result.xml'
            write_sequences(sequences=self.sequence, output_path=input_path)
            cline = NcbiblastnCommandline(cmd='blastn',
                                          query=input_path,
                                          db=self.blastdb,
                                          out=outfile,
                                          evalue=0.00001,
                                          max_target_seqs=5,
                                          strand='plus',
                                          max_hsps=5,
                                          outfmt=5)
            self.stdout, self.stderr = cline()
            return list(NCBIXML.parse(open(outfile)))

<commit_msg>Fix multithreaded blast runs and do not fail on empty Blast output<commit_after>import os
import subprocess
from Bio.Blast import NCBIXML
from Bio.Blast.Applications import NcbiblastnCommandline
from .fasta_io import write_sequences
import temporary


class Blast(object):
    """Hold Blast-related data and methods."""

    def __init__(self, sequence, blastdb=None, reference_fasta=None):
        """
        Blast object for `sequences`.

        Writes out sequences in `sequences` dict as fasta and aligns sequences against `blastdb`.

        >>> from test.helpers import roo_seq
        >>> with temporary.temp_dir() as tempdir:
        ...     reference_fasta = os.path.join(str(tempdir), 'reference.fasta')
        ...     write_sequences({'roo_fragment': roo_seq}, output_path=reference_fasta)
        ...     s = 'ATCGAGAGCGATAAATTATATTTAGGATTTTGTTATCTAAGGCGACAGCTCAAAAACATGTAATTTAAGTGCACACTACATGAGTCAGTCACTTGAGATCGTTCCCCGCCTCCTAAAAT'
        ...     sequence = {'test': s}
        ...     b = Blast(sequence=sequence, reference_fasta=reference_fasta)
        >>> len(b.blast_result[0].alignments) == 1
        True
        """
        self.sequence = sequence
        self.blastdb = blastdb
        self.reference_fasta = reference_fasta
        self.blast_result = self.run()

    def run(self):
        """Run blast command."""
        with temporary.temp_dir() as temp_dir:
            temp_dir = str(temp_dir)
            if not self.blastdb:
                self.blastdb = make_blastdb(self.reference_fasta, dir=temp_dir)
            input_path = os.path.abspath(os.path.join(temp_dir, 'blast.fa'))
            outfile = 'blast_result.xml'
            write_sequences(sequences=self.sequence, output_path=input_path)
            cline = NcbiblastnCommandline(cmd='blastn',
                                          query=input_path,
                                          db=self.blastdb,
                                          out=outfile,
                                          evalue=0.00001,
                                          max_target_seqs=5,
                                          strand='plus',
                                          max_hsps=5,
                                          outfmt=5)
            self.stdout, self.stderr = cline()
            try:
                result = list(NCBIXML.parse(open(outfile)))
            except:
                result = []
            return result


{'fraction_non_alphanumeric': 0.09025878392594151, 'fraction_numerical': 0.004628655585945719, 'mean_word_length': 1.722794959908362, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '733646', 'n_tokens_mistral': 1357, 'n_tokens_neox': 1265, 'n_words': 254}