Package Bio :: Package Application
[hide private]
[frames] | no frames]

Source Code for Package Bio.Application

  1  # Copyright 2001-2004 Brad Chapman. 
  2  # Revisions copyright 2009-2013 by Peter Cock. 
  3  # All rights reserved. 
  4  # This code is part of the Biopython distribution and governed by its 
  5  # license.  Please see the LICENSE file that should have been included 
  6  # as part of this package. 
  7  """General mechanisms to access applications in Biopython. 
  8   
  9  This module is not intended for direct use. It provides the basic objects which 
 10  are subclassed by our command line wrappers, such as: 
 11   
 12   - Bio.Align.Applications 
 13   - Bio.Blast.Applications 
 14   - Bio.Emboss.Applications 
 15   - Bio.Sequencing.Applications 
 16   
 17  These modules provide wrapper classes for command line tools to help you 
 18  construct command line strings by setting the values of each parameter. 
 19  The finished command line strings are then normally invoked via the built-in 
 20  Python module subprocess. 
 21  """ 
 22  from __future__ import print_function 
 23  from Bio._py3k import basestring 
 24   
 25  import os 
 26  import platform 
 27  import sys 
 28  import subprocess 
 29  import re 
 30   
 31  from subprocess import CalledProcessError as _ProcessCalledError 
 32   
 33  from Bio import File 
 34   
 35  #Use this regular expression to test the property names are going to 
 36  #be valid as Python properties or arguments 
 37  _re_prop_name = re.compile(r"^[a-zA-Z][a-zA-Z0-9_]*$") 
 38  assert _re_prop_name.match("t") 
 39  assert _re_prop_name.match("test") 
 40  assert _re_prop_name.match("_test") is None # we don't want private names 
 41  assert _re_prop_name.match("-test") is None 
 42  assert _re_prop_name.match("any-hyphen") is None 
 43  assert _re_prop_name.match("underscore_ok") 
 44  assert _re_prop_name.match("test_name") 
 45  assert _re_prop_name.match("test2") 
 46  #These are reserved names in Python itself, 
 47  _reserved_names = ["and", "del", "from", "not", "while", "as", "elif", 
 48                     "global", "or", "with", "assert", "else", "if", "pass", 
 49                     "yield", "break", "except", "import", "print", "class", 
 50                     "exec", "in", "raise", "continue", "finally", "is", 
 51                     "return", "def", "for", "lambda", "try"] 
 52  #These are reserved names due to the way the wrappers work 
 53  _local_reserved_names = ["set_parameter"] 
 54   
 55   
56 -class ApplicationError(_ProcessCalledError):
57 """Raised when an application returns a non-zero exit status. 58 59 The exit status will be stored in the returncode attribute, similarly 60 the command line string used in the cmd attribute, and (if captured) 61 stdout and stderr as strings. 62 63 This exception is a subclass of subprocess.CalledProcessError. 64 65 >>> err = ApplicationError(-11, "helloworld", "", "Some error text") 66 >>> err.returncode, err.cmd, err.stdout, err.stderr 67 (-11, 'helloworld', '', 'Some error text') 68 >>> print(err) 69 Non-zero return code -11 from 'helloworld', message 'Some error text' 70 71 """
72 - def __init__(self, returncode, cmd, stdout="", stderr=""):
73 self.returncode = returncode 74 self.cmd = cmd 75 self.stdout = stdout 76 self.stderr = stderr
77
78 - def __str__(self):
79 #get first line of any stderr message 80 try: 81 msg = self.stderr.lstrip().split("\n", 1)[0].rstrip() 82 except: 83 msg = "" 84 if msg: 85 return "Non-zero return code %d from %r, message %r" \ 86 % (self.returncode, self.cmd, msg) 87 else: 88 return "Non-zero return code %d from %r" \ 89 % (self.returncode, self.cmd)
90
91 - def __repr__(self):
92 return "ApplicationError(%i, %s, %s, %s)" \ 93 % (self.returncode, self.cmd, self.stdout, self.stderr)
94 95
96 -class AbstractCommandline(object):
97 """Generic interface for constructing command line strings. 98 99 This class shouldn't be called directly; it should be subclassed to 100 provide an implementation for a specific application. 101 102 For a usage example we'll show one of the EMBOSS wrappers. You can set 103 options when creating the wrapper object using keyword arguments - or 104 later using their corresponding properties: 105 106 >>> from Bio.Emboss.Applications import WaterCommandline 107 >>> cline = WaterCommandline(gapopen=10, gapextend=0.5) 108 >>> cline 109 WaterCommandline(cmd='water', gapopen=10, gapextend=0.5) 110 111 You can instead manipulate the parameters via their properties, e.g. 112 113 >>> cline.gapopen 114 10 115 >>> cline.gapopen = 20 116 >>> cline 117 WaterCommandline(cmd='water', gapopen=20, gapextend=0.5) 118 119 You can clear a parameter you have already added by 'deleting' the 120 corresponding property: 121 122 >>> del cline.gapopen 123 >>> cline.gapopen 124 >>> cline 125 WaterCommandline(cmd='water', gapextend=0.5) 126 127 Once you have set the parameters you need, you can turn the object into 128 a string (e.g. to log the command): 129 130 >>> str(cline) 131 Traceback (most recent call last): 132 ... 133 ValueError: You must either set outfile (output filename), or enable filter or stdout (output to stdout). 134 135 In this case the wrapper knows certain arguments are required to construct 136 a valid command line for the tool. For a complete example, 137 138 >>> from Bio.Emboss.Applications import WaterCommandline 139 >>> water_cmd = WaterCommandline(gapopen=10, gapextend=0.5) 140 >>> water_cmd.asequence = "asis:ACCCGGGCGCGGT" 141 >>> water_cmd.bsequence = "asis:ACCCGAGCGCGGT" 142 >>> water_cmd.outfile = "temp_water.txt" 143 >>> print(water_cmd) 144 water -outfile=temp_water.txt -asequence=asis:ACCCGGGCGCGGT -bsequence=asis:ACCCGAGCGCGGT -gapopen=10 -gapextend=0.5 145 >>> water_cmd 146 WaterCommandline(cmd='water', outfile='temp_water.txt', asequence='asis:ACCCGGGCGCGGT', bsequence='asis:ACCCGAGCGCGGT', gapopen=10, gapextend=0.5) 147 148 You would typically run the command line via a standard Python operating 149 system call using the subprocess module for full control. For the simple 150 case where you just want to run the command and get the output: 151 152 stdout, stderr = water_cmd() 153 154 Note that by default we assume the underlying tool is installed on the 155 system $PATH environment variable. This is normal under Linux/Unix, but 156 may need to be done manually under Windows. Alternatively, you can specify 157 the full path to the binary as the first argument (cmd): 158 159 >>> from Bio.Emboss.Applications import WaterCommandline 160 >>> water_cmd = WaterCommandline("C:\Program Files\EMBOSS\water.exe", 161 ... gapopen=10, gapextend=0.5, 162 ... asequence="asis:ACCCGGGCGCGGT", 163 ... bsequence="asis:ACCCGAGCGCGGT", 164 ... outfile="temp_water.txt") 165 >>> print(water_cmd) 166 "C:\Program Files\EMBOSS\water.exe" -outfile=temp_water.txt -asequence=asis:ACCCGGGCGCGGT -bsequence=asis:ACCCGAGCGCGGT -gapopen=10 -gapextend=0.5 167 168 Notice that since the path name includes a space it has automatically 169 been quoted. 170 171 """ 172 #TODO - Replace the above example since EMBOSS doesn't work properly 173 #if installed into a folder with a space like "C:\Program Files\EMBOSS" 174 175 #Note the call example above is not a doctest as we can't handle EMBOSS 176 #(or any other tool) being missing in the unit tests.
177 - def __init__(self, cmd, **kwargs):
178 """Create a new instance of a command line wrapper object.""" 179 # Init method - should be subclassed! 180 # 181 # The subclass methods should look like this: 182 # 183 # def __init__(self, cmd="muscle", **kwargs): 184 # self.parameters = [...] 185 # AbstractCommandline.__init__(self, cmd, **kwargs) 186 # 187 # i.e. There should have an optional argument "cmd" to set the location 188 # of the executable (with a sensible default which should work if the 189 # command is on the path on Unix), and keyword arguments. It should 190 # then define a list of parameters, all objects derived from the base 191 # class _AbstractParameter. 192 # 193 # The keyword arguments should be any valid parameter name, and will 194 # be used to set the associated parameter. 195 self.program_name = cmd 196 try: 197 parameters = self.parameters 198 except AttributeError: 199 raise AttributeError("Subclass should have defined self.parameters") 200 #Create properties for each parameter at run time 201 aliases = set() 202 for p in parameters: 203 if not p.names: 204 assert isinstance(p, _StaticArgument), p 205 continue 206 for name in p.names: 207 if name in aliases: 208 raise ValueError("Parameter alias %s multiply defined" 209 % name) 210 aliases.add(name) 211 name = p.names[-1] 212 if _re_prop_name.match(name) is None: 213 raise ValueError("Final parameter name %s cannot be used as " 214 "an argument or property name in python" 215 % repr(name)) 216 if name in _reserved_names: 217 raise ValueError("Final parameter name %s cannot be used as " 218 "an argument or property name because it is " 219 "a reserved word in python" % repr(name)) 220 if name in _local_reserved_names: 221 raise ValueError("Final parameter name %s cannot be used as " 222 "an argument or property name due to the " 223 "way the AbstractCommandline class works" 224 % repr(name)) 225 226 #Beware of binding-versus-assignment confusion issues 227 def getter(name): 228 return lambda x: x._get_parameter(name)
229 230 def setter(name): 231 return lambda x, value: x.set_parameter(name, value)
232 233 def deleter(name): 234 return lambda x: x._clear_parameter(name) 235 236 doc = p.description 237 if isinstance(p, _Switch): 238 doc += "\n\nThis property controls the addition of the %s " \ 239 "switch, treat this property as a boolean." % p.names[0] 240 else: 241 doc += "\n\nThis controls the addition of the %s parameter " \ 242 "and its associated value. Set this property to the " \ 243 "argument value required." % p.names[0] 244 prop = property(getter(name), setter(name), deleter(name), doc) 245 setattr(self.__class__, name, prop) # magic! 246 for key, value in kwargs.items(): 247 self.set_parameter(key, value) 248
249 - def _validate(self):
250 """Make sure the required parameters have been set (PRIVATE). 251 252 No return value - it either works or raises a ValueError. 253 254 This is a separate method (called from __str__) so that subclasses may 255 override it. 256 """ 257 for p in self.parameters: 258 #Check for missing required parameters: 259 if p.is_required and not(p.is_set): 260 raise ValueError("Parameter %s is not set." 261 % p.names[-1])
262 #Also repeat the parameter validation here, just in case? 263
264 - def __str__(self):
265 """Make the commandline string with the currently set options. 266 267 e.g. 268 >>> from Bio.Emboss.Applications import WaterCommandline 269 >>> cline = WaterCommandline(gapopen=10, gapextend=0.5) 270 >>> cline.asequence = "asis:ACCCGGGCGCGGT" 271 >>> cline.bsequence = "asis:ACCCGAGCGCGGT" 272 >>> cline.outfile = "temp_water.txt" 273 >>> print(cline) 274 water -outfile=temp_water.txt -asequence=asis:ACCCGGGCGCGGT -bsequence=asis:ACCCGAGCGCGGT -gapopen=10 -gapextend=0.5 275 >>> str(cline) 276 'water -outfile=temp_water.txt -asequence=asis:ACCCGGGCGCGGT -bsequence=asis:ACCCGAGCGCGGT -gapopen=10 -gapextend=0.5' 277 """ 278 self._validate() 279 commandline = "%s " % _escape_filename(self.program_name) 280 for parameter in self.parameters: 281 if parameter.is_set: 282 #This will include a trailing space: 283 commandline += str(parameter) 284 return commandline.strip() # remove trailing space
285
286 - def __repr__(self):
287 """Return a representation of the command line object for debugging. 288 289 e.g. 290 >>> from Bio.Emboss.Applications import WaterCommandline 291 >>> cline = WaterCommandline(gapopen=10, gapextend=0.5) 292 >>> cline.asequence = "asis:ACCCGGGCGCGGT" 293 >>> cline.bsequence = "asis:ACCCGAGCGCGGT" 294 >>> cline.outfile = "temp_water.txt" 295 >>> print(cline) 296 water -outfile=temp_water.txt -asequence=asis:ACCCGGGCGCGGT -bsequence=asis:ACCCGAGCGCGGT -gapopen=10 -gapextend=0.5 297 >>> cline 298 WaterCommandline(cmd='water', outfile='temp_water.txt', asequence='asis:ACCCGGGCGCGGT', bsequence='asis:ACCCGAGCGCGGT', gapopen=10, gapextend=0.5) 299 """ 300 answer = "%s(cmd=%s" % (self.__class__.__name__, repr(self.program_name)) 301 for parameter in self.parameters: 302 if parameter.is_set: 303 if isinstance(parameter, _Switch): 304 answer += ", %s=True" % parameter.names[-1] 305 else: 306 answer += ", %s=%s" \ 307 % (parameter.names[-1], repr(parameter.value)) 308 answer += ")" 309 return answer
310
311 - def _get_parameter(self, name):
312 """Get a commandline option value.""" 313 for parameter in self.parameters: 314 if name in parameter.names: 315 if isinstance(parameter, _Switch): 316 return parameter.is_set 317 else: 318 return parameter.value 319 raise ValueError("Option name %s was not found." % name)
320
321 - def _clear_parameter(self, name):
322 """Reset or clear a commandline option value.""" 323 cleared_option = False 324 for parameter in self.parameters: 325 if name in parameter.names: 326 parameter.value = None 327 parameter.is_set = False 328 cleared_option = True 329 if not cleared_option: 330 raise ValueError("Option name %s was not found." % name)
331
332 - def set_parameter(self, name, value = None):
333 """Set a commandline option for a program (OBSOLETE). 334 335 Every parameter is available via a property and as a named 336 keyword when creating the instance. Using either of these is 337 preferred to this legacy set_parameter method which is now 338 OBSOLETE, and likely to be DEPRECATED and later REMOVED in 339 future releases. 340 """ 341 set_option = False 342 for parameter in self.parameters: 343 if name in parameter.names: 344 if isinstance(parameter, _Switch): 345 if value is None: 346 import warnings 347 warnings.warn("For a switch type argument like %s, " 348 "we expect a boolean. None is treated " 349 "as FALSE!" % parameter.names[-1]) 350 parameter.is_set = bool(value) 351 set_option = True 352 else: 353 if value is not None: 354 self._check_value(value, name, parameter.checker_function) 355 parameter.value = value 356 parameter.is_set = True 357 set_option = True 358 if not set_option: 359 raise ValueError("Option name %s was not found." % name)
360
361 - def _check_value(self, value, name, check_function):
362 """Check whether the given value is valid. 363 364 No return value - it either works or raises a ValueError. 365 366 This uses the passed function 'check_function', which can either 367 return a [0, 1] (bad, good) value or raise an error. Either way 368 this function will raise an error if the value is not valid, or 369 finish silently otherwise. 370 """ 371 if check_function is not None: 372 is_good = check_function(value) # May raise an exception 373 assert is_good in [0, 1, True, False] 374 if not is_good: 375 raise ValueError("Invalid parameter value %r for parameter %s" 376 % (value, name))
377
378 - def __setattr__(self, name, value):
379 """Set attribute name to value (PRIVATE). 380 381 This code implements a workaround for a user interface issue. 382 Without this __setattr__ attribute-based assignment of parameters 383 will silently accept invalid parameters, leading to known instances 384 of the user assuming that parameters for the application are set, 385 when they are not. 386 387 >>> from Bio.Emboss.Applications import WaterCommandline 388 >>> cline = WaterCommandline(gapopen=10, gapextend=0.5, stdout=True) 389 >>> cline.asequence = "a.fasta" 390 >>> cline.bsequence = "b.fasta" 391 >>> cline.csequence = "c.fasta" 392 Traceback (most recent call last): 393 ... 394 ValueError: Option name csequence was not found. 395 >>> print(cline) 396 water -stdout -asequence=a.fasta -bsequence=b.fasta -gapopen=10 -gapextend=0.5 397 398 This workaround uses a whitelist of object attributes, and sets the 399 object attribute list as normal, for these. Other attributes are 400 assumed to be parameters, and passed to the self.set_parameter method 401 for validation and assignment. 402 """ 403 if name in ['parameters', 'program_name']: # Allowed attributes 404 self.__dict__[name] = value 405 else: 406 self.set_parameter(name, value) # treat as a parameter
407
408 - def __call__(self, stdin=None, stdout=True, stderr=True, 409 cwd=None, env=None):
410 """Executes the command, waits for it to finish, and returns output. 411 412 Runs the command line tool and waits for it to finish. If it returns 413 a non-zero error level, an exception is raised. Otherwise two strings 414 are returned containing stdout and stderr. 415 416 The optional stdin argument should be a string of data which will be 417 passed to the tool as standard input. 418 419 The optional stdout and stderr argument may be filenames (string), 420 but otherwise are treated as a booleans, and control if the output 421 should be captured as strings (True, default), or ignored by sending 422 it to /dev/null to avoid wasting memory (False). If sent to a file 423 or ignored, then empty string(s) are returned. 424 425 The optional cwd argument is a string giving the working directory 426 to run the command from. See Python's subprocess module documentation 427 for more details. 428 429 The optional env argument is a dictionary setting the environment 430 variables to be used in the new process. By default the current 431 process' environment variables are used. See Python's subprocess 432 module documentation for more details. 433 434 Default example usage: 435 436 from Bio.Emboss.Applications import WaterCommandline 437 water_cmd = WaterCommandline(gapopen=10, gapextend=0.5, 438 stdout=True, auto=True, 439 asequence="a.fasta", bsequence="b.fasta") 440 print "About to run:\n%s" % water_cmd 441 std_output, err_output = water_cmd() 442 443 This functionality is similar to subprocess.check_output() added in 444 Python 2.7. In general if you require more control over running the 445 command, use subprocess directly. 446 447 As of Biopython 1.56, when the program called returns a non-zero error 448 level, a custom ApplicationError exception is raised. This includes 449 any stdout and stderr strings captured as attributes of the exception 450 object, since they may be useful for diagnosing what went wrong. 451 """ 452 if not stdout: 453 stdout_arg = open(os.devnull, "w") 454 elif isinstance(stdout, basestring): 455 stdout_arg = open(stdout, "w") 456 else: 457 stdout_arg = subprocess.PIPE 458 459 if not stderr: 460 stderr_arg = open(os.devnull, "w") 461 elif isinstance(stderr, basestring): 462 if stdout == stderr: 463 stderr_arg = stdout_arg # Write both to the same file 464 else: 465 stderr_arg = open(stderr, "w") 466 else: 467 stderr_arg = subprocess.PIPE 468 469 # We may not need to supply any piped input, but we setup the 470 # standard input pipe anyway as a work around for a python 471 # bug if this is called from a Windows GUI program. For 472 # details, see http://bugs.python.org/issue1124861 473 # 474 # Using universal newlines is important on Python 3, this 475 # gives unicode handles rather than bytes handles. 476 477 # Windows 7 and 8 want shell = True 478 # platform is easier to understand that sys to determine 479 # windows version 480 if sys.platform != "win32": 481 use_shell = True 482 else: 483 win_ver = platform.win32_ver()[0] 484 if win_ver in ["7", "8"]: 485 use_shell = True 486 else: 487 use_shell = False 488 child_process = subprocess.Popen(str(self), stdin=subprocess.PIPE, 489 stdout=stdout_arg, stderr=stderr_arg, 490 universal_newlines=True, 491 cwd=cwd, env=env, 492 shell=use_shell) 493 # Use .communicate as can get deadlocks with .wait(), see Bug 2804 494 stdout_str, stderr_str = child_process.communicate(stdin) 495 if not stdout: 496 assert not stdout_str, stdout_str 497 if not stderr: 498 assert not stderr_str, stderr_str 499 return_code = child_process.returncode 500 501 # Particularly important to close handles on Jython and PyPy 502 # (where garbage collection is less predictable) and on Windows 503 # (where cannot delete files with an open handle): 504 if not stdout or isinstance(stdout, basestring): 505 # We opened /dev/null or a file 506 stdout_arg.close() 507 if not stderr or (isinstance(stderr, basestring) and stdout != stderr): 508 # We opened /dev/null or a file 509 stderr_arg.close() 510 511 if return_code: 512 raise ApplicationError(return_code, str(self), 513 stdout_str, stderr_str) 514 return stdout_str, stderr_str
515 516
517 -class _AbstractParameter:
518 """A class to hold information about a parameter for a commandline. 519 520 Do not use this directly, instead use one of the subclasses. 521 """
522 - def __init__(self):
523 raise NotImplementedError
524
525 - def __str__(self):
526 raise NotImplementedError
527 528
529 -class _Option(_AbstractParameter):
530 """Represent an option that can be set for a program. 531 532 This holds UNIXish options like --append=yes and -a yes, 533 where a value (here "yes") is generally expected. 534 535 For UNIXish options like -kimura in clustalw which don't 536 take a value, use the _Switch object instead. 537 538 Attributes: 539 540 o names -- a list of string names (typically two entries) by which 541 the parameter can be set via the legacy set_parameter method 542 (eg ["-a", "--append", "append"]). The first name in list is used 543 when building the command line. The last name in the list is a 544 "human readable" name describing the option in one word. This 545 must be a valid Python identifier as it is used as the property 546 name and as a keyword argument, and should therefore follow PEP8 547 naming. 548 549 o description -- a description of the option. This is used as 550 the property docstring. 551 552 o filename -- True if this argument is a filename and should be 553 automatically quoted if it contains spaces. 554 555 o checker_function -- a reference to a function that will determine 556 if a given value is valid for this parameter. This function can either 557 raise an error when given a bad value, or return a [0, 1] decision on 558 whether the value is correct. 559 560 o equate -- should an equals sign be inserted if a value is used? 561 562 o is_required -- a flag to indicate if the parameter must be set for 563 the program to be run. 564 565 o is_set -- if the parameter has been set 566 567 o value -- the value of a parameter 568 """
569 - def __init__(self, names, description, filename=False, checker_function=None, 570 is_required=False, equate=True):
571 self.names = names 572 assert isinstance(description, basestring), \ 573 "%r for %s" % (description, names[-1]) 574 self.is_filename = filename 575 self.checker_function = checker_function 576 self.description = description 577 self.equate = equate 578 self.is_required = is_required 579 580 self.is_set = False 581 self.value = None
582
583 - def __str__(self):
584 """Return the value of this option for the commandline. 585 586 Includes a trailing space. 587 """ 588 # Note: Before equate was handled explicitly, the old 589 # code would do either "--name " or "--name=value ", 590 # or " -name " or " -name value ". This choice is now 591 # now made explicitly when setting up the option. 592 if self.value is None: 593 return "%s " % self.names[0] 594 if self.is_filename: 595 v = _escape_filename(self.value) 596 else: 597 v = str(self.value) 598 if self.equate: 599 return "%s=%s " % (self.names[0], v) 600 else: 601 return "%s %s " % (self.names[0], v)
602 603
604 -class _Switch(_AbstractParameter):
605 """Represent an optional argument switch for a program. 606 607 This holds UNIXish options like -kimura in clustalw which don't 608 take a value, they are either included in the command string 609 or omitted. 610 611 o names -- a list of string names (typically two entries) by which 612 the parameter can be set via the legacy set_parameter method 613 (eg ["-a", "--append", "append"]). The first name in list is used 614 when building the command line. The last name in the list is a 615 "human readable" name describing the option in one word. This 616 must be a valid Python identifer as it is used as the property 617 name and as a keyword argument, and should therefore follow PEP8 618 naming. 619 620 o description -- a description of the option. This is used as 621 the property docstring. 622 623 o is_set -- if the parameter has been set 624 625 NOTE - There is no value attribute, see is_set instead, 626 """
627 - def __init__(self, names, description):
628 self.names = names 629 self.description = description 630 self.is_set = False 631 self.is_required = False
632
633 - def __str__(self):
634 """Return the value of this option for the commandline. 635 636 Includes a trailing space. 637 """ 638 assert not hasattr(self, "value") 639 if self.is_set: 640 return "%s " % self.names[0] 641 else: 642 return ""
643 644
645 -class _Argument(_AbstractParameter):
646 """Represent an argument on a commandline. 647 648 The names argument should be a list containing one string. 649 This must be a valid Python identifer as it is used as the 650 property name and as a keyword argument, and should therefore 651 follow PEP8 naming. 652 """
653 - def __init__(self, names, description, filename=False, 654 checker_function=None, is_required=False):
655 #if len(names) != 1: 656 # raise ValueError("The names argument to _Argument should be a " 657 # "single entry list with a PEP8 property name.") 658 self.names = names 659 assert isinstance(description, basestring), \ 660 "%r for %s" % (description, names[-1]) 661 self.is_filename = filename 662 self.checker_function = checker_function 663 self.description = description 664 self.is_required = is_required 665 self.is_set = False 666 self.value = None
667
668 - def __str__(self):
669 if self.value is None: 670 return " " 671 elif self.is_filename: 672 return "%s " % _escape_filename(self.value) 673 else: 674 return "%s " % self.value
675 676
677 -class _ArgumentList(_Argument):
678 """Represent a variable list of arguments on a command line, e.g. multiple filenames.""" 679 #TODO - Option to require at least one value? e.g. min/max count? 680
681 - def __str__(self):
682 assert isinstance(self.value, list), \ 683 "Arguments should be a list" 684 assert self.value, "Requires at least one filename" 685 # A trailing space is required so that parameters following the last filename 686 # do not appear merged. 687 # e.g.: samtools cat in1.bam in2.bam-o out.sam [without trailing space][Incorrect] 688 # samtools cat in1.bam in2.bam -o out.sam [with trailing space][Correct] 689 if self.is_filename: 690 return " ".join(_escape_filename(v) for v in self.value) + " " 691 else: 692 return " ".join(self.value) + " "
693 694
695 -class _StaticArgument(_AbstractParameter):
696 """Represent a static (read only) argument on a commandline. 697 698 This is not intended to be exposed as a named argument or 699 property of a command line wrapper object. 700 """
701 - def __init__(self, value):
702 self.names = [] 703 self.is_required = False 704 self.is_set = True 705 self.value = value
706
707 - def __str__(self):
708 return "%s " % self.value
709 710
711 -def _escape_filename(filename):
712 """Escape filenames with spaces by adding quotes (PRIVATE). 713 714 Note this will not add quotes if they are already included: 715 716 >>> print((_escape_filename('example with spaces'))) 717 "example with spaces" 718 >>> print((_escape_filename('"example with spaces"'))) 719 "example with spaces" 720 """ 721 #Is adding the following helpful 722 #if os.path.isfile(filename): 723 # #On Windows, if the file exists, we can ask for 724 # #its alternative short name (DOS style 8.3 format) 725 # #which has no spaces in it. Note that this name 726 # #is not portable between machines, or even folder! 727 # try: 728 # import win32api 729 # short = win32api.GetShortPathName(filename) 730 # assert os.path.isfile(short) 731 # return short 732 # except ImportError: 733 # pass 734 if " " not in filename: 735 return filename 736 #We'll just quote it - works on Windows, Mac OS X etc 737 if filename.startswith('"') and filename.endswith('"'): 738 #Its already quoted 739 return filename 740 else: 741 return '"%s"' % filename
742 743
744 -def _test():
745 """Run the Bio.Application module's doctests.""" 746 import doctest 747 doctest.testmod(verbose=1)
748 749 if __name__ == "__main__": 750 #Run the doctests 751 _test() 752