Source code for chimera.protocols.protocol_modeller_search

# **************************************************************************
# *
# * Authors:     Marta Martinez (mmmtnez@cnb.csic.es)
# *              Roberto Marabini (roberto@cnb.csic.es)
# *
# * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
# *
# * This program is free software; you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation; either version 2 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# * 02111-1307  USA
# *
# *  All comments concerning this program package may be sent to the
# *  e-mail address 'scipion@cnb.csic.es'
# *
# **************************************************************************

import os
from pwem import *
from pwem.viewers.viewer_chimera import chimeraScriptFileName, Chimera, chimeraPdbTemplateFileName, \
    chimeraMapTemplateFileName, sessionFile
from pyworkflow import VERSION_1_2
from pyworkflow.utils import copyFile

from . import ChimeraProtBase

from pwem.convert.atom_struct import AtomicStructHandler

from pyworkflow.protocol.params import (PointerParam,
                                        StringParam,
                                        MultiPointerParam,
                                        BooleanParam,
                                        EnumParam,
                                        PathParam,
                                        FloatParam,
                                        IntParam)
from pwem.convert.sequence import (SequenceHandler,
                                   saveFileSequencesToAlign,
                                   alignClustalSequences,
                                   alignBioPairwise2Sequences,
                                   alignMuscleSequences)
from collections import OrderedDict

from ..constants import CLUSTALO, MUSCLE
from chimera import Plugin
from chimera.utils import getEnvDictionary


[docs]class ChimeraModelFromTemplate(ChimeraProtBase): """Protocol to model three-dimensional structures of proteins using Modeller. Execute command *scipionwrite #n [prefix stringAddedToFilename] from command line in order to transfer the selected pdb to scipion. Default value is model=#0, model refers to the pdb file.""" _label = 'model from template' _program = "" _version = VERSION_1_2 INFILE1 = "unaligned_1.fasta" OUTFILE1 = "aligned_1.fasta" INFILE2 = "unaligned_2.fasta" OUTFILE2 = "aligned_2.fasta" TWOSEQUENCES = 0 MULTIPLESEQUENCES = 1 ProgramToAlign1 = ['Bio.pairwise2', 'Clustal Omega', 'MUSCLE'] ProgramToAlign2 = ['Clustal Omega', 'MUSCLE'] OptionForAligning = ['None', 'Additional sequences to align', 'Provide your own sequence alignment'] OptionForDataBase = ['PDB', 'NR'] OptionForMatrix = ['BLOSUM45', 'BLOSUM50', 'BLOSUM62', 'BLOSUM80', 'BLOSUM90', 'PAM30', 'PAM70', 'PAM250', 'IDENTITY'] # --------------------------- DEFINE param functions -------------------- def _defineParams(self, form, doHelp=False): form.addSection(label='Input') section = form.getSection('Input') section.addParam('addTemplate', BooleanParam, default=True, label='Do you already have a template?', help='"Yes": Option by default. Select this option in case ' 'you already have a template to model your target ' 'sequence.\n"No": Select this option if you want to ' 'search for a template with which model your target ' 'sequence. Generation of multimeric models is not ' 'allowed selecting this option.\n') section.addParam('pdbFileToBeRefined', PointerParam, pointerClass="AtomStruct", allowsNull=True, important=True, condition='addTemplate == True', label='Atomic structure used as template', help="PDBx/mmCIF file template used as basic atomic " "structure to model your specific sequence.") section.addParam('inputStructureChain', StringParam, label="Chain ", allowsNull=True, important=True, condition='addTemplate == True', help="Select a particular chain of the atomic " "structure.") section.addParam('inputSequence1', PointerParam, pointerClass="Sequence", label='Target sequence', allowsNull=True, important=True, help="Input the aminoacid sequence to align with the " "structure template sequence.") section.addParam('dataBase', EnumParam, choices=self.OptionForDataBase, condition='addTemplate == False', label="Protein sequence database:", default=0, help="Select a protein sequence database to search " "for templates:\nPDB: Experimentally determined structures " "in the " "Protein Data Bank.\nNR: NCBI 'non-redundant'database. " "It contains GenBank translation proteins, PDB sequences, " "SwissProt proteins + PIR + PRF. Since NR is much larger " "than PDB, it takes longer to search.\n") section.addParam('similarityMatrix', EnumParam, choices=self.OptionForMatrix, condition='addTemplate == False', label="Similarity matrix:", default=2, help="Select a similarity matrix to use for alignment " "scoring.\n") section.addParam('cutoffValue', FloatParam, condition='addTemplate == False', label="cutoff evalue:", default=1e-3, help="Least significant expectation value needed to " "qualify the retrieved element as a hit.\n") section.addParam('maxSeqs', IntParam, condition='addTemplate == False', label="Maximum number of sequences:", default=100, help="Maximum number of sequences to retrieve " "from the database.\n") section.addParam('optionForAligning1', EnumParam, choices=self.OptionForAligning, condition='addTemplate == True', label="Options to improve the alignment:", default=0, help="None: Option by default. Only the template and the " "target sequences will be included in the alignment. " "This option is recommendable when these two sequences " "are very similar. Otherwise, select any of the two " "additional options:\n" "Additional sequences to align: Select this option " "if you want to add some more sequences to accomplish " "the alignment.\n" "Provide your own sequence alignment: Your alignment" "should include both the target and the template " "sequences.\n") section.addParam('inputYourOwnSequenceAlignment1', PathParam, pointerClass="File", allowsNull=False, condition='addTemplate == True and optionForAligning1 == 2', label='Sequence alignment input', help="Input your own sequence alignment.\n" "ChimeraX allowed formats accessible here: " "https://www.cgl.ucsf.edu/chimerax/docs/user/commands/open.html#sequence ") section.addParam('inputSequencesToAlign1', MultiPointerParam, pointerClass="Sequence", allowsNull=True, condition='addTemplate == True and optionForAligning1 == 1', label='Other sequences to align', help="In case you need to load more sequences to " "align, you can load them here.") section.addParam('inputProgramToAlign1_1', EnumParam, choices=self.ProgramToAlign1, label="Alignment tool for two sequences:", default=0, condition='addTemplate == True and optionForAligning1 == 0', help="Select a program to accomplish the sequence" "alignment:\n\nBiophyton module " "Bio.pairwise2 (" "http://biopython.org/DIST/docs/api/" "Bio.pairwise2-module.html). Built-in " "program to align two " "sequences. The global " "alignment algorithm from the EMBOSS suite " "has been implemented with match/mismatch " "scores of 3/-1 and gap penalties " "(open/extend) of " "3/2.\n\nClustal Omega " "program (http://www.clustal.org/omega/, " "https://doi.org/10.1038/msb.2011.75): " "Multiple sequence alignment tool. Install " "clustalo if you choose this option for " "the first time by 'sudo apt-get install " "clustalo'.\n\nMUSCLE program stands for " "MUltiple Sequence Comparison by " "Log- Expectation(" "http://www.drive5.com/muscle/muscle.html, " "https://doi.org/10.1093/nar/gkh340). " "Install muscle if you choose this option " "for the first time by 'sudo apt install " "muscle'.") section.addParam('inputProgramToAlign2_1', EnumParam, choices=self.ProgramToAlign2, label="Multiple alignment tool:", default=0, condition='addTemplate == True and optionForAligning1 == 1', help="Select a program to accomplish the sequence" "alignment:\n\nClustal Omega " "program (http://www.clustal.org/omega/, " "https://doi.org/10.1038/msb.2011.75): " "Multiple sequence alignment tool. Install " "clustalo if you choose this option for " "the first time by 'sudo apt-get install " "clustalo'.\n\nMUSCLE program stands for " "MUltiple Sequence Comparison by " "Log- Expectation(" "http://www.drive5.com/muscle/muscle.html, " "https://doi.org/10.1093/nar/gkh340). " "Install muscle if you choose this option " "for the first time by 'sudo apt install " "muscle'.") section.addParam('additionalTargetSequence', BooleanParam, default=False, condition='addTemplate == True', label='Additional target sequence to include?', help='Select YES if you want to add an additional ' 'target sequence to model according a different ' 'chain of the structure template. This ' 'option is recommendable when you want to model ' 'the two interacting elements of a particular complex' ' at the same time.') section.addParam('selectStructureChain', StringParam, condition='addTemplate == True and ' 'additionalTargetSequence == True', label="Chain ", allowsNull=True, important=True, help="Select a particular chain of the atomic " "structure.") section.addParam('inputSequence2', PointerParam, pointerClass="Sequence", condition='addTemplate == True and ' 'additionalTargetSequence == True', label='Target sequence', allowsNull=True, important=True, help="Input the aminoacid sequence to align with the " "structure template sequence.") section.addParam('optionForAligning2', EnumParam, choices=self.OptionForAligning, condition='addTemplate == True and ' 'additionalTargetSequence == True', label="Options to improve the alignment:", default=0, help="None: Option by default. Only the template and the " "target sequences will be included in the alignment. " "This option is recommendable when these two sequences " "are very similar. Otherwise, select any of the two " "additional options:\n" "Additional sequences to align: Select this option " "if you want to add some more sequences to accomplish " "the alignment.\n" "Provide your own sequence alignment: Your alignment" "should include both the target and the template " "sequences.\n") section.addParam('inputYourOwnSequenceAlignment2', PathParam, pointerClass="File", allowsNull=False, condition='addTemplate == True and ' 'optionForAligning2 == 2 and ' 'additionalTargetSequence == True', label='Sequence alignment input', help="Input your own sequence alignment.\n" "ChimeraX allowed formats accessible here: " "https://www.cgl.ucsf.edu/chimerax/docs/user/commands/open.html#sequence ") section.addParam('inputSequencesToAlign2', MultiPointerParam, pointerClass="Sequence", allowsNull=True, condition='addTemplate == True and ' 'optionForAligning2 == 1 and ' 'additionalTargetSequence == True', label='Other sequences to align', help="In case you need to load more sequences to " "align, you can load them here.") section.addParam('inputProgramToAlign1_2', EnumParam, choices=self.ProgramToAlign1, label="Alignment tool for two sequences:", default=0, condition='addTemplate == True and ' 'optionForAligning2 == 0 and ' 'additionalTargetSequence == True', help="Select a program to accomplish the sequence" "alignment:\n\nBiophyton module " "Bio.pairwise2 (" "http://biopython.org/DIST/docs/api/" "Bio.pairwise2-module.html). Built-in " "program to align two " "sequences. The global " "alignment algorithm from the EMBOSS suite " "has been implemented with match/mismatch " "scores of 3/-1 and gap penalties " "(open/extend) of " "3/2.\n\nClustal Omega " "program (http://www.clustal.org/omega/, " "https://doi.org/10.1038/msb.2011.75): " "Multiple sequence alignment tool. Install " "clustalo if you choose this option for " "the first time by 'sudo apt-get install " "clustalo'.\n\nMUSCLE program stands for " "MUltiple Sequence Comparison by " "Log- Expectation(" "http://www.drive5.com/muscle/muscle.html, " "https://doi.org/10.1093/nar/gkh340). " "Install muscle if you choose this option " "for the first time by 'sudo apt install " "muscle'.") section.addParam('inputProgramToAlign2_2', EnumParam, choices=self.ProgramToAlign2, label="Multiple alignment tool:", default=0, condition='addTemplate == True and ' 'optionForAligning2 == 1 and ' 'additionalTargetSequence == True', help="Select a program to accomplish the sequence" "alignment:\n\nClustal Omega " "program (http://www.clustal.org/omega/, " "https://doi.org/10.1038/msb.2011.75): " "Multiple sequence alignment tool. Install " "clustalo if you choose this option for " "the first time by 'sudo apt-get install " "clustalo'.\n\nMUSCLE program stands for " "MUltiple Sequence Comparison by " "Log- Expectation(" "http://www.drive5.com/muscle/muscle.html, " "https://doi.org/10.1093/nar/gkh340). " "Install muscle if you choose this option " "for the first time by 'sudo apt install " "muscle'.") section.addParam('extraCommands', StringParam, default = '', condition = 'False', label = 'Extra commands for chimera viewer', help = "Add extra commands in cmd file. Use for testing") form.addSection(label='Help') form.addLine("Step 1:\nIn the sequence window your target " "sequence (and other additional sequences that you " "want to use in the alignment) will appear aligned to " "the template's sequence. Select in the sequence window " "menu:\nTools -> Sequence -> Modeller Comparative;\nA new " "window for Comparative Modeling with Modeller will " "appear. Select your specific template(s) as the Sequence " "alignments and the target(s)sequence as the sequence " "to be modeled" + ''' . To run Modeller via web service write the Modeller license key supplied (Academic user can register free of charge to receive a license key). Finally, press OK. \nWAITING TIME: (you may see the status of your job in chimera main window, lower left corner.)\n\nStep 2:\nWhen the process finished, 5 models will be automatically superimposed onto the template and model scores will appear in Modeller Results window. In Chimera Model panel you will have: #1 (coordinate axes); #2 ( template); #3.1 to 3.5 (models).Choose the one you like the best, for example model #3.1. To save it in Scipion, we need to change the model ID. In Chimera main menu: Favorites -> Command Line, write *rename #3.1 id #4*. Then, you will see in Model panel that selected model #3.1 renamed to #3. Save it as first guess in Scipion by executing the Chimera command *scipionwrite [model] #n [prefix XX]*. In our example *scipionwrite #4 pefix model_3_1_*.\n When you use the command line scipionwrite, the Chimera session will be saved by default. Additionally, you can save the Chimera session whenever you want by executing the command *scipionss*. You will be able to restore the saved session by using the protocol chimera restore session (SCIPION menu: Tools/Calculators/chimera restore session). Once you have save your favorite model you can press Quit in the Modeller Results window.''') # --------------------------- INSERT steps functions --------------------
[docs] def prerequisitesStep(self): if self.addTemplate: # read PDB fileName = self._readPDB() # get pdb sequence import json chainIdDict = json.loads(self.inputStructureChain.get()) userSeq = self.inputSequence1.get() # SEQ object from Scipion inFile = self.INFILE1 outFile = self.OUTFILE1 addSeq = self.optionForAligning1.get() yourAlignment = self.inputYourOwnSequenceAlignment1.get() inputSeqAlign = self.inputSequencesToAlign1 programToAlign1 = self.inputProgramToAlign1_1 programToAlign2 = self.inputProgramToAlign2_1 self.prePreRequisites(fileName, chainIdDict, userSeq, inFile, outFile, addSeq, yourAlignment, inputSeqAlign, programToAlign1, programToAlign2) self.selectedChain1 = self.selectedChain if self.additionalTargetSequence.get() is True: chainIdDict = json.loads(self.selectStructureChain.get()) userSeq = self.inputSequence2.get() # SEQ object from Scipion inFile = self.INFILE2 outFile = self.OUTFILE2 addSeq = self.optionForAligning2.get() yourAlignment = self.inputYourOwnSequenceAlignment2.get() inputSeqAlign = self.inputSequencesToAlign2 programToAlign1 = self.inputProgramToAlign1_2 programToAlign2 = self.inputProgramToAlign2_2 self.prePreRequisites(fileName, chainIdDict, userSeq, inFile, outFile, addSeq, yourAlignment, inputSeqAlign, programToAlign1, programToAlign2) self.selectedChain2 = self.selectedChain else: userSeq = self.inputSequence1.get() # SEQ object from Scipion # get target sequence imported by the user outFile = self.OUTFILE1 self.targetSeqID1 = self.preTemplate(userSeq, outFile)
[docs] def prePreRequisites(self, fileName, chainIdDict, userSeq, inFile, outFile, addSeq, yourAlignment, inputSeqAlign, programToAlign1, programToAlign2): # get sequence of structure chain with id chainId (selected by the user) self.selectedModel = chainIdDict['model'] self.selectedChain = chainIdDict['chain'] # self.selectedModel = chainId.split(',')[0].split(':')[1].strip() # self.selectedChain = chainId.split(',')[1].split(':')[1].strip() print("Selected chain: %s from model: %s from structure: %s" \ % (self.selectedChain, self.selectedModel, os.path.basename(fileName))) # Bio.Seq.Seq object structureSeq = self.structureHandler.getSequenceFromChain( self.selectedModel, self.selectedChain) # obtain a seqID for our PDB sequence structSeqID = self.structureHandler.getFullID(self.selectedModel, self.selectedChain) # END PDB sequence # start user imported target sequence # get target sequence imported by the user targetSeqID = userSeq.getId() # ID associated to SEQ object (str) userSequence = userSeq.getSequence() # sequence associated to # that SEQ object (str) # transformation of this sequence (str) in a Bio.Seq.Seq object: seqHandler = SequenceHandler(userSequence, isAminoacid=userSeq.getIsAminoacids()) targetSeq = seqHandler._sequence # Bio.Seq.Seq object # creation of Dic of IDs and sequences SeqDic = OrderedDict() SeqDic[structSeqID] = structureSeq SeqDic[targetSeqID] = targetSeq # align sequences and save them to disk, -this will be chimera input- # get all sequences in a fasta file inFile = self._getInFastaSequencesFile(inFile) outFile = self._getOutFastaSequencesFile(outFile) # get the alignment of sequences if addSeq == 0: saveFileSequencesToAlign(SeqDic, inFile) inputSeqAlign = None if programToAlign1.get() == \ self.ProgramToAlign1.index('Bio.pairwise2'): # Only the two first sequences will be included in the alignment self.alignment = alignBioPairwise2Sequences( structSeqID, structureSeq, targetSeqID, targetSeq, outFile) else: # All the sequences will be included in the alignment if programToAlign1.get() == \ self.ProgramToAlign1.index('Clustal Omega'): cline = alignClustalSequences(inFile, outFile) else: cline = alignMuscleSequences(inFile, outFile) args = '' self.runJob(cline, args) elif addSeq == 1: # if there are additional sequences imported by the user if inputSeqAlign is not None: for seq in inputSeqAlign: seq = seq.get() ID = seq.getId() sequence = seq.getSequence() seqHandler = SequenceHandler(sequence, isAminoacid=seq.getIsAminoacids()) otherSeq = seqHandler._sequence # Bio.Seq.Seq object SeqDic[ID] = otherSeq # align sequences and save them to disk, -this will be chimera input- # get all sequences in a fasta file # inFile = self._getInFastaSequencesFile() saveFileSequencesToAlign(SeqDic, inFile) # outFile = self._getOutFastaSequencesFile() # All the sequences will be included in the alignment if programToAlign2 == self.ProgramToAlign2.index( 'Clustal Omega'): cline = alignClustalSequences(inFile, outFile) else: cline = alignMuscleSequences(inFile, outFile) args = '' self.runJob(cline, args) else: aligmentFile = os.path.basename(yourAlignment) outFile = os.path.join(self._getExtraPath(), aligmentFile) copyFile(yourAlignment, outFile)
[docs] def preTemplate(self, userSeq, outFile): userSequence = userSeq.getSequence() # sequence associated to # that SEQ object (str) targetSeqID = userSeq.getId() # ID associated to SEQ object (str) # transformation of this sequence (str) in a Bio.Seq.Seq object: seqHandler = SequenceHandler(userSequence, isAminoacid=userSeq.getIsAminoacids()) targetSeq = seqHandler._sequence # Bio.Seq.Seq object # creation of Dic of IDs and sequences SeqDic = OrderedDict() SeqDic[targetSeqID] = targetSeq outFile = self._getOutFastaSequencesFile(outFile) saveFileSequencesToAlign(SeqDic, outFile) return targetSeqID
def _readPDB(self): self.structureHandler = AtomicStructHandler() fileName = os.path.abspath(self.pdbFileToBeRefined.get( ).getFileName()) self.structureHandler.read(fileName) return fileName def _getInFastaSequencesFile(self, inFile): INFILENAME = self._getTmpPath(inFile) return os.path.abspath(INFILENAME) def _getOutFastaSequencesFile(self, outFile): OUTFILENAME = self._getExtraPath(outFile) return os.path.abspath(OUTFILENAME)
[docs] def runChimeraStep(self): # building script file including the coordinate axes and the input # volume with samplingRate and Origin information f = open(self._getTmpPath(chimeraScriptFileName), "w") # building coordinate axes dim = 150 # eventually we will create a PDB library that # computes PDB dim sampling = 1. tmpFileName = os.path.abspath(self._getTmpPath("axis_input.bild")) Chimera.createCoordinateAxisFile(dim, bildFileName=tmpFileName, sampling=sampling) f.write("open %s\n" % tmpFileName) f.write("cofr 0,0,0\n") # set center of coordinates # input vol with its origin coordinates pdbModelCounter = 1 if (not self.addTemplate and self.inputSequence1.get() is not None and self._getOutFastaSequencesFile is not None): alignmentFile1 = self._getOutFastaSequencesFile(self.OUTFILE1) f.write("open %s\n" % alignmentFile1) f.write("blastprotein %s:%s database %s matrix %s " "cutoff %.3f maxSeqs %d log true\n" % (alignmentFile1.split("/")[-1], self.targetSeqID1, self.OptionForDataBase[int(self.dataBase)], self.OptionForMatrix[int(self.similarityMatrix)], self.cutoffValue, self.maxSeqs)) if (hasattr(self, 'pdbFileToBeRefined') and self.pdbFileToBeRefined.get() is not None): pdbModelCounter += 1 pdbFileToBeRefined = self.pdbFileToBeRefined.get() f.write("open %s\n" % os.path.abspath( pdbFileToBeRefined.getFileName())) if pdbFileToBeRefined.hasOrigin(): x, y, z = (pdbFileToBeRefined.getOrigin().getShifts()) f.write("move %0.2f,%0.2f,%0.2f model #%d " "coord #0\n" % (x, y, z, pdbModelCounter)) # Alignment of sequence and structure if (hasattr(self, 'inputSequence1') and hasattr(self, 'inputStructureChain')): if (self.inputSequence1.get() is not None and self.inputStructureChain.get() is not None): pdbModelCounter = 2 if str(self.selectedModel) != '0': f.write("select #%s.%s/%s\n" % (pdbModelCounter, str(self.selectedModel + 1), str(self.selectedChain1))) else: f.write("select #%s/%s\n" % (pdbModelCounter, str(self.selectedChain1))) if self._getOutFastaSequencesFile is not None: alignmentFile1 = self._getOutFastaSequencesFile(self.OUTFILE1) f.write("open %s\n" % alignmentFile1) f.write("sequence disassociate #%s %s\n" % (pdbModelCounter, alignmentFile1.split("/")[-1])) if str(self.selectedModel) != '0': f.write("sequence associate #%s.%s/%s %s:1\n" % (pdbModelCounter, str(self.selectedModel + 1), str(self.selectedChain1), alignmentFile1.split("/")[-1])) else: f.write("sequence associate #%s/%s %s:1\n" % (pdbModelCounter, str(self.selectedChain1), alignmentFile1.split("/")[-1])) if (self.additionalTargetSequence.get() is True and self.inputSequence2.get() is not None and self.inputStructureChain.get() is not None): f.write("select clear\n") f.write("select #%s/%s,%s\n" % (pdbModelCounter, str(self.selectedChain1), str(self.selectedChain2))) if self._getOutFastaSequencesFile is not None: alignmentFile2 = self._getOutFastaSequencesFile(self.OUTFILE2) f.write("open %s\n" % alignmentFile2) f.write("sequence disassociate #%s %s\n" % (pdbModelCounter, alignmentFile2.split("/")[-1])) if str(self.selectedModel) != '0': f.write("sequence associate #%s.%s/%s %s:1\n" % (pdbModelCounter, str(self.selectedModel + 1), str(self.selectedChain2), alignmentFile2.split("/")[-1])) else: f.write("sequence associate #%s/%s %s:1\n" % (pdbModelCounter, str(self.selectedChain2), alignmentFile2.split("/")[-1])) # run the text: _chimeraScriptFileName = os.path.abspath( self._getTmpPath(chimeraScriptFileName)) if len(self.extraCommands.get()) > 2: f.write(self.extraCommands.get()) args = " --nogui " + _chimeraScriptFileName else: args = " " + _chimeraScriptFileName f.close() self._log.info('Launching: ' + Plugin.getProgram() + ' ' + args) # run in the background cwd = os.path.abspath(self._getExtraPath()) Plugin.runChimeraProgram(Plugin.getProgram(), args, cwd=cwd, extraEnv=getEnvDictionary(self))
def _validate(self): # Check that CLUSTALO or MUSCLE program exists errors = super(ChimeraModelFromTemplate, self)._validate() if not (self.is_tool(CLUSTALO) or self.is_tool(MUSCLE)): errors.append("Clustal-omega and MUSCLE programs missing.\n " "You need at least one of them to run this program.\n" "Please install Clustal-omega and/or MUSCLE:\n" " sudo apt-get install clustalo\n" " sudo apt-get install muscle") return errors