Back to index

python-biopython  1.60
_paml.py
Go to the documentation of this file.
00001 # Copyright (C) 2011 by Brandon Invergo (b.invergo@gmail.com)
00002 # This code is part of the Biopython distribution and governed by its
00003 # license. Please see the LICENSE file that should have been included
00004 # as part of this package.
00005 
00006 import os
00007 import subprocess
00008 
00009 try:
00010     from os.path import relpath as _relpath
00011 except ImportError:
00012     #New in Python 2.6
00013     def _relpath(path, start=None):
00014         """Return a relative version of a path.
00015 
00016         Implementation by James Gardner in his BareNecessities
00017         package, under MIT licence.
00018 
00019         With a fix for Windows where posixpath.sep (and functions like
00020         join) use the Unix slash not the Windows slash.
00021         """
00022         import posixpath
00023         if start is None:
00024             start = posixpath.curdir
00025         else:
00026             start = start.replace(os.path.sep, posixpath.sep)
00027         if not path:
00028             raise ValueError("no path specified")
00029         else:
00030             path = path.replace(os.path.sep, posixpath.sep)
00031         start_list = posixpath.abspath(start).split(posixpath.sep)
00032         path_list = posixpath.abspath(path).split(posixpath.sep)
00033         # Work out how much of the filepath is shared by start and path.
00034         i = len(posixpath.commonprefix([start_list, path_list]))
00035         rel_list = [posixpath.pardir] * (len(start_list)-i) + path_list[i:]
00036         if not rel_list:
00037             return posixpath.curdir.replace(posixpath.sep, os.path.sep)
00038         return posixpath.join(*rel_list).replace(posixpath.sep, os.path.sep)
00039 
00040 class PamlError(EnvironmentError):
00041     """paml has failed. Run with verbose = True to view the error
00042 message"""
00043 
00044 class Paml(object):
00045     
00046     def __init__(self, alignment = None, working_dir = None,
00047                 out_file = None):
00048         if working_dir is None:
00049             self.working_dir = os.getcwd()
00050         else:
00051             self.working_dir = working_dir
00052         if alignment is not None:
00053             if not os.path.exists(alignment):
00054                 raise IOError, "The specified alignment file does not exist."
00055         self.alignment = alignment
00056         self.out_file = out_file
00057         
00058     def write_ctl_file(self):
00059         pass
00060         
00061     def read_ctl_file(self):
00062         pass
00063         
00064     def print_options(self):
00065         """Print out all of the options and their current settings."""
00066         for option in self._options.items():
00067             print "%s = %s" % (option[0], option[1])
00068  
00069     def set_options(self, **kwargs):
00070         """Set the value of an option. 
00071         
00072         This function abstracts the options dict to prevent the user from 
00073         adding options that do not exist or mispelling options.
00074         """
00075         for option, value in kwargs.items():
00076             if not self._options.has_key(option):
00077                 raise KeyError, "Invalid option: " + option
00078             else:
00079                 self._options[option] = value
00080         
00081     def get_option(self, option):
00082         """Return the value of an option."""
00083         if not self._options.has_key(option):
00084             raise KeyError, "Invalid option: " + option
00085         else:
00086             return self._options.get(option)
00087     
00088     def get_all_options(self):
00089         """Return the values of all the options."""        
00090         return self._options.items()
00091         
00092     def _set_rel_paths(self):
00093         """Convert all file/directory locations to paths relative to the current working directory.
00094         
00095         paml requires that all paths specified in the control file be
00096         relative to the directory from which it is called rather than 
00097         absolute paths.
00098         """
00099         if self.working_dir is not None:
00100             self._rel_working_dir = _relpath(self.working_dir)
00101         if self.alignment is not None:
00102             self._rel_alignment = _relpath(self.alignment, 
00103                 self.working_dir)
00104         if self.out_file is not None:
00105             self._rel_out_file = _relpath(self.out_file, self.working_dir)
00106         
00107     def run(self, ctl_file, verbose, command):
00108         """Run a paml program using the current configuration and then parse the results. 
00109         
00110         Return a process signal so the user can determine if
00111         the execution was successful (return code 0 is successful, -N
00112         indicates a failure). The arguments may be passed as either 
00113         absolute or relative paths, despite the fact that paml 
00114         requires relative paths.
00115         """
00116         if self.alignment is None:
00117             raise ValueError, "Alignment file not specified."
00118         if not os.path.exists(self.alignment):
00119             raise IOError, "The specified alignment file does not exist."
00120         if self.out_file is None:
00121             raise ValueError, "Output file not specified."
00122         if self.working_dir is None:
00123             raise ValueError, "Working directory not specified."
00124         # Get the current working directory
00125         cwd = os.getcwd()
00126         # Move to the desired working directory
00127         if not os.path.exists(self.working_dir):
00128             os.mkdir(self.working_dir)
00129         os.chdir(self.working_dir)
00130         # If no external control file was specified...
00131         if ctl_file is None:
00132             # Dynamically build a control file
00133             self.write_ctl_file()
00134             if verbose:
00135                 result_code = subprocess.call([command, self.ctl_file])
00136             else:
00137                 # To suppress output, redirect it to a pipe to nowhere
00138                 result_code = subprocess.call([command, self.ctl_file],
00139                     stdout=subprocess.PIPE)
00140         else:
00141             if not os.path.exists(ctl_file):
00142                 raise IOError, "The specified control file does not exist."
00143             if verbose:
00144                 result_code = subprocess.call([command, ctl_file])
00145             else:
00146                 result_code = subprocess.call([command, ctl_file],
00147                     stdout=subprocess.PIPE)
00148         os.chdir(cwd)
00149         if result_code > 0:
00150             # If the program fails for any reason
00151             raise PamlError, \
00152             "%s has failed (return code %i). Run with verbose = True to view error message" \
00153             % (command, result_code)
00154         if result_code < 0:
00155             # If the paml process is killed by a signal somehow
00156             raise EnvironmentError, "The %s process was killed (return code %i)." \
00157                   % (command, result_code)