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