#!/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('<>', self.Validate) self.blasts.bind('<>', 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()