MSG = 'A python package to run this executable is required,'
BIO = 'biopython'
BIO_BGZF = 'biopython with Bgzf support'
    NCBIXML = create_fake_class(MSG + BIO)
    NCBIWWW = create_fake_class(MSG + BIO)
def create_fake_class(msg):
        def __init__(self, *args, **kwargs):
def create_fake_funct(msg):
    def FakeRequiredfunct(*args, **kwargs):
    class FakePythonRequiredClass(object): def get_binary_path(binary_name):
    '''It return the path to the proper binary. It looks on platform and
    architecture to decide it.

    Fails if there is not binary for that architecture
    '''
    if get_setting('USE_EXTERNAL_BIN_PREFIX'):
        ext_binary_name = get_setting('EXTERNAL_BIN_PREFIX') + binary_name
        if os.path.exists(ext_binary_name):
            return ext_binary_name

    if not get_setting('ADD_PATH_TO_EXT_BIN'):
        # I have to check if the binary is on my current directory.
        # If it is there use it, else assumes that it is on the path
        if os.path.exists(os.path.join(os.getcwd(), ext_binary_name)):
            return os.path.join(os.getcwd(), ext_binary_name)
        # return binary_name

    system = platform.system().lower()
    if system == 'windows':
        binary_name += '.exe'
    arch = platform.architecture()[0]

    join = os.path.join

    third_party_path = get_setting('THIRD_PARTY_DIR')

    binary_path = os.path.abspath(join(third_party_path, 'bin', system, arch,
                                       binary_name))
    if os.path.exists(binary_path):
        return binary_path
    elif arch == '64bit':
        arch = '32bit'
        binary_path = os.path.abspath(join(third_party_path, 'bin', system,
                                           arch, binary_name))
        if os.path.exists(binary_path):
            return binary_path

    # At this point there is not available binary for the working platform
    # Is the binary really in the path?
    if which(binary_name):
        return binary_name

    msg = '{} not found in the path. Please install it to use ngs_crumbs'
    raise MissingBinaryError(msg.format(binary_name)) def popen(*args, **kwargs):
    'It spawns a process with subprocess.Popen'
    try:
        return Popen(*args, **kwargs)
    except OSError, error:
        msg = 'The binary "%s" is not in the path.' % args[0][0]
        if 'No such file' in str(error):
            raise MissingBinaryError(msg) def check_process_finishes(process, binary, stdout=None, stderr=None):
    'It checks that the given process finishes OK, otherwise raises an Error'

    stdout_msg, stderr_msg = process.communicate()

    returncode = process.returncode
    if returncode == 0:
        return
    elif returncode is None:
        msg = 'The process for {:s} is still running with PID'
        msg = msg.format(binary, process.PID)
        raise RuntimeError(msg)

    if stdout and not stdout_msg:
        stdout.flush()
        stdout_msg = open(stdout.name).read()
    if stderr and not stderr_msg:
        stderr.flush()
        stderr_msg = open(stderr.name).read()
    msg = '{:s} had a problem running\n'.format(binary)
    if stdout_msg:
        msg += 'stdout:\n{:s}\n'.format(stdout_msg)
    if stderr_msg:
        msg += 'stderr:\n{:s}\n'.format(stderr_msg)
    raise ExternalBinaryError(msg) FIVE_PRIME = "5'" THREE_PRIME = "3'" def get_description(seq):
    seq_class = seq.kind
    seq = seq.object
    if seq_class == SEQITEM:
        title_items = seq.lines[0].split(' ', 1)
        desc = title_items[1] if len(title_items) == 2 else None
    elif seq_class == SEQRECORD:
        desc = seq.description
        if desc == '<unknown description>':  # BioPython default
            return None
    return desc def get_name(seq):
    if 'SeqRecord' in seq.__class__.__name__:
        seq_class = SEQRECORD
    else:
        seq_class = seq.kind
        seq = seq.object
    if seq_class == SEQITEM:
        name = seq.name
    elif seq_class == SEQRECORD:
        name = seq.id
    return name def get_str_seq(seq):
    seq_class = seq.kind
    if seq_class == SEQITEM:
        seq = seq.object.lines[1].strip()
    elif seq_class == SEQRECORD:
        seq = str(seq.object.seq)
    return seq.strip() def write_seqs(seqs, fhand=None, file_format=None):
    'It writes the given sequences'
    if fhand is None:
        fhand = NamedTemporaryFile(suffix='.' + file_format.replace('-', '_'))

    seqs, seqs2 = tee(seqs)
    try:
        seq = seqs2.next()
    except StopIteration:
        # No sequences to write, so we're done
        return fhand
    del seqs2
    seq_class = seq.kind
    if seq_class == SEQITEM:
        _write_seqitems(seqs, fhand, file_format)
    elif seq_class == SEQRECORD:
        seqs = (seq.object for seq in seqs)
        _write_seqrecords(seqs, fhand, file_format)
    else:
        raise ValueError('Unknown class for seq: ' + seq_class)
    return fhand def read_seqs(fhands, out_format=None, prefered_seq_classes=None):
    'It returns a stream of seqs in different codings: seqrecords, seqitems...'

    if not prefered_seq_classes:
        prefered_seq_classes = [SEQITEM, SEQRECORD]
    try:
        in_format = get_format(fhands[0])
    except FileIsEmptyError:
        return []
    # seqitems is incompatible with different input and output formats
    # or when in_format != a fasta or fastq
    if ((out_format not in (None, GUESS_FORMAT) and in_format != out_format
         and SEQITEM in prefered_seq_classes) or
        (in_format not in ('fasta',) + SANGER_FASTQ_FORMATS +
         ILLUMINA_FASTQ_FORMATS)):
        prefered_seq_classes.pop(prefered_seq_classes.index(SEQITEM))

    if not prefered_seq_classes:
        msg = 'No valid seq class left or prefered'
        raise ValueError(msg)

    for seq_class in prefered_seq_classes:
        if seq_class == SEQITEM:
            try:
                return _read_seqitems(fhands)
            except NotImplementedError:
                continue
        elif seq_class == SEQRECORD:
            try:
                seqs = _read_seqrecords(fhands)
                return assing_kind_to_seqs(SEQRECORD, seqs, None)
            except NotImplementedError:
                continue
        else:
            raise ValueError('Unknown class for seq: ' + seq_class)
    raise RuntimeError('We should not be here, fixme') class Blaster(object):
    '''It matches the given SeqRecords against a blast database.
    It needs iterable with seqrecords and a blast dabatase
    '''

    def __init__(self, seqrecords, blastdb, program, dbtype=None, params=None,
                 filters=None, remote=False):
        self.program = program
        if params is None:
            params = {}
        self.params = params
        if filters is None:
            filters = []
        self.filters = filters
        self._remote = remote
        if dbtype not in (NUCL, PROT, None):
            raise ValueError('dbtype must be NUCL, PROT or None (we guess)')
        self._blasts = self._look_for_blast_matches(seqrecords, blastdb,
                                                    dbtype)

    def _look_for_blast_matches(self, seqrecords, blastdb, dbtype):
        'it makes the blast and filters the results'
        blasts, blast_fhand = _do_blast_2(blastdb, seqrecords, self.program,
                                          params=self.params, dbtype=dbtype,
                                          remote=self._remote)
        # print open(blast_fhand.name).read()
        if self.filters is not None:
            blasts = filter_alignments(blasts, config=self.filters)

        blasts = {blast['query']['name']: blast for blast in blasts}
        blast_fhand.close()
        return blasts

    def get_matched_segments(self, seqrecord_name):
        'It returns the matched segments for the given query (SeqRecord) name.'
        try:
            blast = self._blasts[seqrecord_name]
        except KeyError:
            # There was no match in the blast
            return None

        match_parts = [mp for m in blast['matches'] for mp in m['match_parts']]
        segments = covered_segments_from_match_parts(match_parts,
                                                     in_query=False)
        return segments

    @property
    def blasts(self):
        'It returns the blasts alignment results.'
        # we trust the clients not to mess with this dict or its nested
        # structure, to deepcopy would be a waste of resources in a
        # well-behaved world
        return self._blasts def get_setting(key):
    'It returns the value for one setting'
    return _settings[key]
import subprocess
import os.path
from tempfile import NamedTemporaryFile
from random import randint
from crumbs.utils.optional_modules import SeqFeature, FeatureLocation
from crumbs.utils.bin_utils import (get_binary_path, popen,
                                    check_process_finishes)
from crumbs.utils.tags import FIVE_PRIME, THREE_PRIME
from crumbs.seq.seq import get_description, get_name, get_str_seq
from crumbs.seq.seqio import write_seqs, read_seqs
from crumbs.blast import Blaster
from crumbs.settings import get_setting
            poly_count = 0
            mismatch_count += 1
        if poly_count >= min_len:
            result = tail_len + 1
        if mismatch_count > max_cont_mismatches:
            break
        tail_len += 1
    if result and location == FIVE_PRIME:
        start = 0
        end = result
        result = start, end
    elif result and location == THREE_PRIME:
        end = len(seq)
        start = end - result
        result = start, end
    else:
        result = None
    return result


def _annotate_polya(seq, min_len, max_cont_mismatches):
    'It annotates the polyA with the EMBOSS trimest method'
    str_seq = get_str_seq(seq)
    polya = _detect_polya_tail(str_seq, THREE_PRIME, min_len,
                               max_cont_mismatches)
    polyt = _detect_polya_tail(str_seq, FIVE_PRIME, min_len,
                               max_cont_mismatches)
    a_len = polya[1] - polya[0] if polya else 0
    t_len = polyt[1] - polyt[0] if polyt else 0
    chosen_tail = None
    if a_len > t_len:
        chosen_tail = 'A'
    elif t_len > a_len:
        chosen_tail = 'T'
    elif a_len and a_len == t_len:
        if randint(0, 1):
            chosen_tail = 'A'
        else:
            chosen_tail = 'T'
    if chosen_tail:
        strand = 1 if chosen_tail == 'A' else -1
        start, end = polya if chosen_tail == 'A' else polyt
        feat = SeqFeature(location=FeatureLocation(start, end, strand),
                          type='polyA_sequence')
        # We're assuming that the seq has a SeqRecord in it
        seq.object.features.append(feat)


class PolyaAnnotator(object):
    'It annotates the given seqrecords with poly-A or poly-T regions'
    def __init__(self, min_len=get_setting('POLYA_ANNOTATOR_MIN_LEN'),
                max_cont_mismatches=get_setting('POLYA_ANNOTATOR_MISMATCHES')):
        '''It inits the class.

        min_len - minimum number of consecutive As (or Ts) to extend the tail
        max_cont_mismatches - maximum number of consecutive no A (or Ts) to
                              break a tail.
        '''
        self._min_len = min_len
        self._max_cont_mismatches = max_cont_mismatches

    def __call__(self, seqrecords):
        'It runs the actual annotations'
        max_cont_mismatches = self._max_cont_mismatches
        min_len = self._min_len

        for seq in seqrecords:
            _annotate_polya(seq, min_len, max_cont_mismatches)
        return seqrecords


class BlastAnnotator(object):
    'It annotates using blast'
    def __init__(self, blastdb, program, dbtype=None, filters=None,
                 params=None, remote=False):
        'Initializes the class'
        self.blastdb = blastdb
        self._program = program
        self._filters = [] if filters is None else filters
        self._params = params
        self._dbtype = dbtype
        self._remote = remote

    def __call__(self, seqrecords):
        'It does the work'
        if not seqrecords:
            return seqrecords
        matcher = Blaster(seqrecords, self.blastdb, self._program,
                               self._dbtype, filters=self._filters,
                               params=self._params, remote=self._remote)
        blasts = matcher.blasts
        blastdb = os.path.basename(self.blastdb)
        for seqrecord in seqrecords:
            align_result = blasts.get(get_name(seqrecord), None)
            if not align_result:
                continue
            match_counter = 0
            for match in align_result['matches']:
                subject = match['subject']['name']
                match_counter += 1
                for match_part in  match['match_parts']:
                    if match_part['subject_end'] < match_part['subject_start']:
                        strand = -1
                        subject_start = match_part['subject_end']
                        subject_end = match_part['subject_start']
                    else:
                        strand = 1
                        subject_start = match_part['subject_start']
                        subject_end = match_part['subject_end']

                    query_start = match_part['query_start']
                    query_end = match_part['query_end']
                    qualifiers = {}
                    qualifiers['Target'] = {'start': subject_start,
                                            'end': subject_end,
                                            'name': subject}
                    qualifiers['score'] = match_part['scores']['expect']
                    qualifiers['identity'] = match_part['scores']['identity']
                    qualifiers['blastdb'] = blastdb
                    location = FeatureLocation(query_start, query_end, strand)

                    feature = SeqFeature(location=location, type='match_part',