Back to index

python-biopython  1.60
test_Prank_tool.py
Go to the documentation of this file.
00001 """
00002 Unittests for Bio.Align.Applications interface for PRANK
00003 
00004 This code is part of the Biopython distribution and governed by its
00005 license.  Please see the LICENSE file that should have been included
00006 as part of this package.
00007 """
00008 
00009 import sys
00010 import os
00011 import unittest
00012 import subprocess
00013 from Bio import AlignIO
00014 from Bio import SeqIO
00015 from Bio import MissingExternalDependencyError
00016 from Bio.Align.Applications import PrankCommandline
00017 from Bio.Nexus.Nexus import NexusError
00018 
00019 #Try to avoid problems when the OS is in another language
00020 os.environ['LANG'] = 'C'
00021 
00022 prank_exe = None
00023 if sys.platform=="win32":
00024     try:
00025         #This can vary depending on the Windows language.
00026         prog_files = os.environ["PROGRAMFILES"]
00027     except KeyError:
00028         prog_files = r"C:\Program Files"
00029     #For Windows, PRANK just comes as a zip file which contains the
00030     #prank.exe file which the user could put anywhere.  We'll try a few
00031     #sensible locations under Program Files... and then the full path.
00032     likely_dirs = ["", #Current dir
00033                    prog_files,
00034                    os.path.join(prog_files,"Prank")] + sys.path
00035     for folder in likely_dirs:
00036         if os.path.isdir(folder):
00037             if os.path.isfile(os.path.join(folder, "prank.exe")):
00038                 prank_exe = os.path.join(folder, "prank.exe")
00039                 break
00040         if prank_exe : break
00041 else:
00042     import commands
00043     output = commands.getoutput("prank")
00044     if "not found" not in output and "prank" in output.lower():
00045         prank_exe = "prank"
00046 if not prank_exe:
00047     raise MissingExternalDependencyError(\
00048         "Install PRANK if you want to use the Bio.Align.Applications wrapper.")
00049 
00050 class PrankApplication(unittest.TestCase):
00051     
00052     def setUp(self):
00053         self.infile1 = "Fasta/fa01"
00054 
00055     def tearDown(self):
00056         """
00057         output.1.dnd  output.1.fas  output.1.xml  output.2.dnd  output.2.fas  output.2.xml
00058         """
00059         if os.path.isfile("output.1.dnd"):
00060             os.remove("output.1.dnd")
00061         if os.path.isfile("output.1.fas"):
00062             os.remove("output.1.fas")
00063         if os.path.isfile("output.1.xml"):
00064             os.remove("output.1.xml")
00065         if os.path.isfile("output.2.dnd"):
00066             os.remove("output.2.dnd")
00067         if os.path.isfile("output.2.fas"):
00068             os.remove("output.2.fas")
00069         if os.path.isfile("output.2.xml"):
00070             os.remove("output.2.xml")
00071         if os.path.isfile("output.1.nex"):
00072             os.remove("output.1.nex")
00073         if os.path.isfile("output.2.nex"):
00074             os.remove("output.2.nex")
00075 
00076     def test_Prank_simple(self):
00077         """Simple round-trip through app with infile.
00078         output.?.??? files written to cwd - no way to redirect
00079         """
00080         cmdline = PrankCommandline(prank_exe)
00081         cmdline.set_parameter("d", self.infile1)
00082         self.assertEqual(str(cmdline), prank_exe + " -d=Fasta/fa01")
00083         self.assertEqual(str(eval(repr(cmdline))), str(cmdline))
00084         output, error = cmdline()
00085         self.assertEqual(error, "")
00086         self.assertTrue("Total time" in output)
00087 
00088     def test_Prank_simple_with_NEXUS_output(self):
00089         """Simple round-trip through app with infile, output in NEXUS
00090         output.?.??? files written to cwd - no way to redirect
00091         """
00092         records = list(SeqIO.parse(self.infile1,"fasta"))
00093         #Try using keyword argument,
00094         cmdline = PrankCommandline(prank_exe, d=self.infile1, noxml=True)
00095         #Try using a property,
00096         cmdline.d = self.infile1
00097         cmdline.f = 17 # NEXUS format
00098         cmdline.set_parameter("notree", True)
00099         self.assertEqual(str(cmdline), prank_exe + \
00100                          " -d=Fasta/fa01 -f=17 -noxml -notree")
00101         self.assertEqual(str(eval(repr(cmdline))), str(cmdline))
00102         stdout, stderr = cmdline()
00103         self.assertTrue("Total time" in stdout)
00104         self.assertEqual(stderr, "")
00105         try:
00106             align = AlignIO.read("output.2.nex", "nexus")
00107             for old, new in zip(records, align):
00108                 #Old versions of Prank reduced name to 9 chars
00109                 self.assertTrue(old.id==new.id or old.id[:9]==new.id)
00110                 #infile1 has alignment gaps in it
00111                 self.assertEqual(str(new.seq).replace("-",""),
00112                                  str(old.seq).replace("-",""))
00113         except NexusError:
00114             #See bug 3119,
00115             #Bio.Nexus can't parse output from prank v100701 (1 July 2010)
00116             pass
00117 
00118     def test_Prank_complex_command_line(self):
00119         """Round-trip with complex command line."""
00120         cmdline = PrankCommandline(prank_exe)
00121         cmdline.set_parameter("d", self.infile1)
00122         cmdline.set_parameter("-noxml", True)
00123         cmdline.set_parameter("notree", True)
00124         cmdline.set_parameter("-gaprate", 0.321)
00125         cmdline.set_parameter("gapext", 0.6)
00126         cmdline.set_parameter("-dots", 1) #i.e. True
00127         #Try using a property:
00128         cmdline.kappa = 3
00129         cmdline.skipins = True
00130         cmdline.set_parameter("-once", True)
00131         cmdline.realbranches = True
00132         self.assertEqual(str(cmdline), prank_exe + " -d=Fasta/fa01 -noxml" + \
00133                          " -notree -dots -gaprate=0.321 -gapext=0.6 -kappa=3" + \
00134                          " -once -skipins -realbranches")
00135         self.assertEqual(str(eval(repr(cmdline))), str(cmdline))
00136         stdout, stderr = cmdline()
00137         self.assertTrue("Total time" in stdout, stdout)
00138 
00139 
00140 class PrankConversion(unittest.TestCase):
00141     def setUp(self):
00142         #As these reads are all 36, it can be seen as pre-aligned:
00143         self.input = "Quality/example.fasta"
00144         self.output = 'temp with space' #prefix, PRANK will pick extensions
00145 
00146     def conversion(self, prank_number, prank_ext, format):
00147         """Get PRANK to do a conversion, and check it with SeqIO."""
00148         filename = "%s.%s" % (self.output, prank_ext)
00149         if os.path.isfile(filename):
00150             os.remove(filename)
00151         cmdline = PrankCommandline(prank_exe, d=self.input,
00152                                    convert=True, f=prank_number,
00153                                    o='"%s"' % self.output)
00154         self.assertEqual(str(cmdline), prank_exe \
00155                          + ' -d=%s' % self.input \
00156                          + ' -o="%s"' % self.output \
00157                          + ' -f=%i' % prank_number \
00158                          + ' -convert')
00159         self.assertEqual(str(eval(repr(cmdline))), str(cmdline))
00160         message, error = cmdline()
00161         self.assertTrue(("PRANK: converting '%s' to '%s'" % (self.input, filename)) \
00162                         in message, message)
00163         self.assertEqual(error, "")
00164         self.assertTrue(os.path.isfile(filename))
00165         old = AlignIO.read(self.input, "fasta")
00166         #Hack...
00167         if format=="phylip":
00168             for record in old:
00169                 record.id = record.id[:10]
00170         new = AlignIO.read(filename, format)
00171         assert len(old) == len(new)
00172         for old_r, new_r in zip(old, new):
00173             self.assertEqual(old_r.id, new_r.id)
00174             self.assertEqual(str(old_r.seq), str(new_r.seq))
00175         os.remove(filename)
00176         
00177     def test_convert_to_fasta(self):
00178         """Convert FASTA to FASTA format."""
00179         self.conversion(8, "fas", "fasta")
00180 
00181     #Prank v.100701 seems to output an invalid file here...
00182     #def test_convert_to_phylip32(self):
00183     #    """Convert FASTA to PHYLIP 3.2 format."""
00184     #    self.conversion(11, "phy", "phylip")
00185 
00186     def test_convert_to_phylip(self):
00187         """Convert FASTA to PHYLIP format."""
00188         self.conversion(12, "phy", "phylip")
00189 
00190     #PRANK truncated the record names in the matrix block. An error?
00191     #def test_convert_to_paup_nexus(self):
00192     #    """Convert FASTA to PAUP/NEXUS."""
00193     #    self.conversion(17, "nex", "nexus")
00194 
00195     #We don't support format 18, PAML
00196 
00197 
00198 if __name__ == "__main__":
00199     runner = unittest.TextTestRunner(verbosity = 2)
00200     unittest.main(testRunner=runner)