File: xbb_blast.py

package info (click to toggle)
python-biopython 1.68%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 46,860 kB
  • ctags: 13,237
  • sloc: python: 160,306; xml: 93,216; ansic: 9,118; sql: 1,208; makefile: 155; sh: 63
file content (206 lines) | stat: -rw-r--r-- 7,563 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/usr/bin/env python
# Copyright 2000 by Thomas Sicheritz-Ponten.
# Copyrigth 2016 by Markus Piotrowski.
# All rights reserved.
# This code is part of the Biopython distribution and governed by its
# license.  Please see the LICENSE file that should have been included
# as part of this package.

# Created: Thu Jul 13 14:07:25 2000
# thomas@cbs.dtu.dk, http://www.cbs.dtu.dk/thomas
# File: xbb_blast.py

from __future__ import print_function

import glob
import os
import sys

try:  # Python 2
    import Tkinter as tk
    import ttk
    import tkFileDialog as filedialog
    import tkMessageBox as messagebox
except ImportError:  # Python 3
    import tkinter as tk
    import tkinter.ttk as ttk
    from tkinter import filedialog
    from tkinter import messagebox


from xbb_utils import NotePad
import xbb_blastbg


class BlastIt(object):

    nin, pin = [], []
    blast_ok = False
    blast_path = ''

    def __init__(self, seq, parent=None):
        self.seq = seq
        self.parent = parent
        self.toplevel = tk.Toplevel(parent)
        self.toplevel.title('BLAST parameters')
        if not self.get_blast_databases() or not self.get_blast_binaries():
            return
        self.Choices()
        self.dbs.bind('<<ComboboxSelected>>', self.Validate)
        self.blasts.bind('<<ComboboxSelected>>', self.Validate)

    def get_blast_databases(self):
        """Try to locate the BLAST databases and put into lists."""
        if not (BlastIt.nin and BlastIt.pin):
            pin, nin = [], []

            try:
                pin.extend(glob.glob(os.environ['BLASTDB'] + '/*.pin'))
            except KeyError:
                pass
            pin.extend(glob.glob('C:*.pin'))

            try:
                nin.extend(glob.glob(os.environ['BLASTDB'] + '/*.nin'))
            except KeyError:
                pass

            # If no system variable BLASTDB exists, give user the chance to
            # locate his database folder:
            if not(nin and pin):
                database_folder = filedialog.askdirectory(
                    title='Please locate your BLAST database(s) folder:')
                nin.extend(glob.glob(database_folder + '/*.nin'))
                pin.extend(glob.glob(database_folder + '/*.pin'))
                if not (nin and pin):
                    messagebox.showerror('xbb tools', 'This folder does not'
                                         ' contain any BLAST databases!')
                    self.toplevel.destroy()
                    return False

            self.pin = [os.path.splitext(x)[0] for x in pin]
            self.nin = [os.path.splitext(x)[0] for x in nin]

            BlastIt.pin = self.pin
            BlastIt.nin = self.nin

        return True

    def get_blast_binaries(self):
        """Test if BLAST binaries are in PATH or let user locate them."""
        if not BlastIt.blast_ok:
            # Test if blast binaries are in path
            if os.system('blastn -version'):  # Return of non-zero means error
                self.blast_path = filedialog.askdirectory(
                    title='Please locate your BLAST program folder:')
                self.blast_path += os.sep
                if os.system('{}blastn -version'.format(self.blast_path)):
                    messagebox.showerror(
                        'xbb tools', 'Wrong folder or missing BLAST'
                        ' binaries!\n  To run BLAST you must install the '
                        ' standalone BLAST binaries.')
                    self.toplevel.destroy()
                    return False
                else:
                    BlastIt.blast_ok = True

            else:  # BLAST binaries are in PATH
                BlastIt.blast_ok = True
                self.blast_path = ''
        BlastIt.blast_path = self.blast_path
        self.toplevel.lift()
        return True

    def database_readable(self, db_paths):
        """Return the name of the blast database without path and extension."""
        db_names = [entry.split(os.sep)[-1].split('.')[0]
                    for entry in db_paths]
        return db_names

    def convert_dbname_to_dbpath(self, db_name):
        """Return the full path for a given blast database name."""
        database_path = ''
        for database in self.nin:
            if database.endswith(db_name):
                database_path = database
                break
        for database in self.pin:
            if database.endswith(db_name):
                database_path = database
                break
        return database_path

    def Choices(self):
        self.blast_string = tk.StringVar()
        self.blast_string.set('blastn')
        self.cf = ttk.Frame(self.toplevel)
        self.cf.pack(side='top', expand=1, fill='x')
        self.dbs_frame = ttk.LabelFrame(self.cf, text='Databases')
        self.dbs_frame.pack(side='left', padx=5, pady=5, expand=1, fill='x')
        nin_values = self.database_readable(self.nin)
        pin_values = self.database_readable(self.pin)
        self.dbs = ttk.Combobox(self.dbs_frame, exportselection=0,
                                values=nin_values + pin_values)
        self.dbs.current(0)

        self.blast_frame = ttk.LabelFrame(self.cf, text='BLAST programs')
        self.blast_frame.pack(side='left', padx=5, pady=5, expand=1, fill='x')
        self.blasts = ttk.Combobox(self.blast_frame, exportselection=0,
                                   textvariable=self.blast_string,
                                   values=['blastn', 'blastp', 'blastx',
                                           'tblastn', 'tblastx'])

        self.dbs.pack(side='left', padx=5, pady=5, expand=1, fill='x')
        self.blasts.pack(side='left', padx=5, pady=5, expand=1, fill='x')

        self.option_f = ttk.LabelFrame(self.cf, text='Command line options')
        self.option_f.pack(side='left', padx=5, pady=5, expand=1, fill='x')
        self.option = ttk.Entry(self.option_f)
        self.option.pack(side='left', padx=5, pady=5, fill='x', expand=1)
        self.ok = ttk.Button(self.cf, text='Run', command=self._Run,
                             state='disabled')
        self.ok.pack(side='right')

        self.Validate()

    def Validate(self, *args):
        db = self.convert_dbname_to_dbpath(self.dbs.get())
        prog = self.blasts.get()
        if (prog in ['blastn', 'tblastx', 'tblastn']) == (db in self.nin):
            self.ok.config(state='normal')
        elif (prog in ['blastp', 'blastx']) == (db in self.pin):
            self.ok.config(state='normal')
        else:
            self.ok.config(state='disabled')

    def _Run(self):
        """Setup options for Blast commandline (PRIVATE)."""
        command_options = self.option.get()
        options = ''
        if len(command_options.strip()):
            options = command_options.strip()

        db = self.convert_dbname_to_dbpath(self.dbs.get())
        prog = self.blast_path + self.blasts.get()
        self.command_data = [self.seq, prog, db, options]

        self.Run()

    def Run(self):
        self.notepad = NotePad()
        tid = self.notepad.tid

        self.toplevel.destroy()
        blastbg = xbb_blastbg.BlastDisplayer(self.command_data, tid)
        blastbg.RunCommand()


if __name__ == '__main__':
    try:
        seq = sys.argv[1]
    except IndexError:  # Started script without providing a sequence
        seq = 'ATGACAAAGCTAATTATTCACTTGGTTTCAGACTCTTCTGTGCAAACTGC'
    win = tk.Tk()
    win.title('Dummy windows for BLAST test')
    test = BlastIt(seq)
    win.mainloop()