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