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