--- /dev/null
+"""General mechanisms to access applications in biopython.
+"""
+import os, sys
+import StringIO
+
+from Bio import File
+
+def generic_run(commandline):
+ """Run an application with the given commandline.
+
+ This expects a pre-built commandline that derives from
+ AbstractCommandline, and returns a ApplicationResult object
+ to get results from a program, along with handles of the
+ standard output and standard error.
+
+ WARNING - This will read in the full program output into memory!
+ This may be in issue when the program write a large amount of
+ data to standard output.
+ """
+ # print str(commandline)
+
+ #Try and use subprocess (available in python 2.4+)
+ try :
+ import subprocess, sys
+ #We don't need to supply any piped input, but we setup the
+ #standard input pipe anyway as a work around for a python
+ #bug if this is called from a Windows GUI program. For
+ #details, see http://bugs.python.org/issue1124861
+ child = subprocess.Popen(str(commandline),
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ shell=(sys.platform!="win32"))
+ child.stdin.close()
+ r = child.stdout
+ e = child.stderr
+
+ r_out = r.read()
+ e_out = e.read()
+ r.close()
+ e.close()
+
+ # capture error code
+ error_code = child.wait()
+
+ except ImportError :
+ #For python 2.3 can't use subprocess, using popen2 instead
+ #(deprecated in python 2.6)
+ import popen2
+ if sys.platform[:3]=='win':
+ # Windows does not have popen2.Popen3
+ r, w, e = popen2.popen3(str(commandline))
+
+ r_out = r.read()
+ e_out = e.read()
+ w.close()
+ r.close()
+ e.close()
+
+ # No way to get the error code; setting it to a dummy variable
+ error_code = 0
+
+ else:
+ child = popen2.Popen3(str(commandline), 1)
+ # get information and close the files, so if we call this function
+ # repeatedly we won't end up with too many open files
+
+ # here are the file descriptors
+ r = child.fromchild
+ w = child.tochild
+ e = child.childerr
+
+ r_out = r.read()
+ e_out = e.read()
+ w.close()
+ r.close()
+ e.close()
+
+ # capture error code
+ error_code = os.WEXITSTATUS(child.wait())
+
+ return ApplicationResult(commandline, error_code), \
+ File.UndoHandle(StringIO.StringIO(r_out)), \
+ File.UndoHandle(StringIO.StringIO(e_out))
+
+class ApplicationResult:
+ """Make results of a program available through a standard interface.
+
+ This tries to pick up output information available from the program
+ and make it available programmatically.
+ """
+ def __init__(self, application_cl, return_code):
+ """Intialize with the commandline from the program.
+ """
+ self._cl = application_cl
+
+ # provide the return code of the application
+ self.return_code = return_code
+
+ # get the application dependent results we can provide
+ # right now the only results we handle are output files
+ self._results = {}
+
+ for parameter in self._cl.parameters:
+ if "file" in parameter.param_types and \
+ "output" in parameter.param_types:
+ if parameter.is_set:
+ self._results[parameter.names[-1]] = parameter.value
+
+ def get_result(self, output_name):
+ """Retrieve result information for the given output.
+ """
+ return self._results[output_name]
+
+ def available_results(self):
+ """Retrieve a list of all available results.
+ """
+ result_names = self._results.keys()
+ result_names.sort()
+ return result_names
+
+class AbstractCommandline:
+ """Generic interface for running applications from biopython.
+
+ This class shouldn't be called directly; it should be subclassed to
+ provide an implementation for a specific application.
+ """
+ def __init__(self):
+ self.program_name = ""
+ self.parameters = []
+
+ def __str__(self):
+ """Make the commandline with the currently set options.
+ """
+ commandline = "%s " % self.program_name
+ for parameter in self.parameters:
+ if parameter.is_required and not(parameter.is_set):
+ raise ValueError("Parameter %s is not set." % parameter.names)
+ if parameter.is_set:
+ commandline += str(parameter)
+
+ return commandline
+
+ def set_parameter(self, name, value = None):
+ """Set a commandline option for a program.
+ """
+ set_option = 0
+ for parameter in self.parameters:
+ if name in parameter.names:
+ if value is not None:
+ self._check_value(value, name, parameter.checker_function)
+ parameter.value = value
+ parameter.is_set = 1
+ set_option = 1
+
+ if set_option == 0:
+ raise ValueError("Option name %s was not found." % name)
+
+ def _check_value(self, value, name, check_function):
+ """Check whether the given value is valid.
+
+ This uses the passed function 'check_function', which can either
+ return a [0, 1] (bad, good) value or raise an error. Either way
+ this function will raise an error if the value is not valid, or
+ finish silently otherwise.
+ """
+ if check_function is not None:
+ is_good = check_function(value)
+ if is_good in [0, 1]: # if we are dealing with a good/bad check
+ if not(is_good):
+ raise ValueError(
+ "Invalid parameter value %r for parameter %s" %
+ (value, name))
+
+class _AbstractParameter:
+ """A class to hold information about a parameter for a commandline.
+
+ Do not use this directly, instead use one of the subclasses.
+
+ Attributes:
+
+ o names -- a list of string names by which the parameter can be
+ referenced (ie. ["-a", "--append", "append"]). The first name in
+ the list is considered to be the one that goes on the commandline,
+ for those parameters that print the option. The last name in the list
+ is assumed to be a "human readable" name describing the option in one
+ word.
+
+ o param_type -- a list of string describing the type of parameter,
+ which can help let programs know how to use it. Example descriptions
+ include 'input', 'output', 'file'
+
+ o checker_function -- a reference to a function that will determine
+ if a given value is valid for this parameter. This function can either
+ raise an error when given a bad value, or return a [0, 1] decision on
+ whether the value is correct.
+
+ o description -- a description of the option.
+
+ o is_required -- a flag to indicate if the parameter must be set for
+ the program to be run.
+
+ o is_set -- if the parameter has been set
+
+ o value -- the value of a parameter
+ """
+ def __init__(self, names = [], types = [], checker_function = None,
+ is_required = 0, description = ""):
+ self.names = names
+ self.param_types = types
+ self.checker_function = checker_function
+ self.description = description
+ self.is_required = is_required
+
+ self.is_set = 0
+ self.value = None
+
+class _Option(_AbstractParameter):
+ """Represent an option that can be set for a program.
+
+ This holds UNIXish options like --append=yes and -a yes
+ """
+ def __str__(self):
+ """Return the value of this option for the commandline.
+ """
+ # first deal with long options
+ if self.names[0].find("--") >= 0:
+ output = "%s" % self.names[0]
+ if self.value is not None:
+ output += "=%s " % self.value
+ else:
+ output += " "
+ # now short options
+ elif self.names[0].find("-") >= 0:
+ output = "%s " % self.names[0]
+ if self.value is not None:
+ output += "%s " % self.value
+ else:
+ raise ValueError("Unrecognized option type: %s" % self.names[0])
+
+ return output
+
+class _Argument(_AbstractParameter):
+ """Represent an argument on a commandline.
+ """
+ def __str__(self):
+ if self.value is not None:
+ return "%s " % self.value
+ else:
+ return " "