Package Biskit :: Module tools
[hide private]
[frames] | no frames]

Source Code for Module Biskit.tools

   1  ## 
   2  ## Biskit, a toolkit for the manipulation of macromolecular structures 
   3  ## Copyright (C) 2004-2005 Raik Gruenberg & Johan Leckner 
   4  ## 
   5  ## This program is free software; you can redistribute it and/or 
   6  ## modify it under the terms of the GNU General Public License as 
   7  ## published by the Free Software Foundation; either version 2 of the 
   8  ## License, or any later version. 
   9  ## 
  10  ## This program is distributed in the hope that it will be useful, 
  11  ## but WITHOUT ANY WARRANTY; without even the implied warranty of 
  12  ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
  13  ## General Public License for more details. 
  14  ## 
  15  ## You find a copy of the GNU General Public License in the file 
  16  ## license.txt along with this program; if not, write to the Free 
  17  ## Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  18  ## 
  19  ## 
  20  ## last $Author: leckner $ 
  21  ## last $Date: 2006/12/21 09:33:39 $ 
  22  ## $Revision: 2.16 $ 
  23   
  24  """ 
  25  simply -  everyday tools 
  26  """ 
  27   
  28  import sys, string 
  29  import os.path as osp 
  30  import shutil 
  31  import operator 
  32  import os, cPickle  ## for Load and Dump 
  33  import tempfile 
  34  import traceback 
  35  from inspect import getframeinfo 
  36  from time import localtime 
  37  import Numeric 
  38  import types 
  39  import glob 
  40  import subprocess 
  41   
42 -class ToolsError( Exception ):
43 pass
44
45 -class PickleError( ToolsError ):
46 pass
47
48 -def errWriteln(s):
49 """ 50 print s to standard error with line feed. 51 52 @param s: string 53 @type s: str 54 """ 55 sys.stderr.write(s+'\n') 56 sys.stderr.flush()
57 58
59 -def errWrite(s):
60 """ 61 print s to standard error. 62 63 @param s: string 64 @type s: str 65 """ 66 sys.stderr.write(s) 67 sys.stderr.flush()
68 69
70 -def flushPrint(s):
71 """ 72 print s without line break and flush standard out. 73 74 @param s: string 75 @type s: str 76 """ 77 sys.stdout.write(s) 78 sys.stdout.flush()
79 80
81 -def lastError():
82 """ 83 Collect type and line of last exception. 84 85 @return: '<ExceptionType> in line <lineNumber>:<Exception arguments>' 86 @rtype: String 87 """ 88 try: 89 trace = sys.exc_info()[2] 90 why = sys.exc_info()[1] 91 try: 92 why = sys.exc_info()[1].args 93 except: 94 pass 95 file = getframeinfo( trace.tb_frame )[0] 96 97 result = "%s in %s line %i:\n\t%s." % ( str(sys.exc_type), 98 file, trace.tb_lineno, str(why) ) 99 100 finally: 101 trace = None 102 103 return result
104 105
106 -def lastErrorTrace( limit=None ):
107 tb = sys.exc_info()[2] 108 109 lines = traceback.extract_tb( tb, None ) 110 111 result = '' 112 for l in lines: 113 pyFile = stripFilename( l[0] ) 114 result += '%s: %i (%s) %s\n' % (pyFile, l[1],l[2],l[3]) 115 116 return result
117 118
119 -def dictAdd( dic, key, value ):
120 """ 121 Add value to dic, create list, if dic has already value in key. 122 123 @param key: dictionary key 124 @type key: str 125 @param value: value 126 @type value: any 127 """ 128 if key in dic: 129 old = dic[key] 130 131 if type( old ) != list and value != old: 132 dic[ key ] = [ old ] + [ value ] 133 else: 134 if type( old ) == list and value not in old: 135 dic[ key ] = old + [ value ] 136 137 else: 138 dic[key] = value
139 140
141 -def absfile( filename, resolveLinks=1 ):
142 """ 143 Get absolute file path:: 144 - expand ~ to user home, change 145 - expand ../../ to absolute path 146 - resolve links 147 - add working directory to unbound files ('ab.txt'->'/home/raik/ab.txt') 148 149 @param filename: name of file 150 @type filename: str 151 @param resolveLinks: eliminate any symbolic links (default: 1) 152 @type resolveLinks: 1|0 153 154 @return: absolute path or filename 155 @rtype: string 156 157 @raise ToolsError: if a ~user part does not translate to an existing path 158 """ 159 if not filename: 160 return filename 161 r = osp.abspath( osp.expanduser( filename ) ) 162 163 if '~' in r: 164 raise ToolsError, 'Could not expand user home in %s' % filename 165 166 if resolveLinks: 167 r = osp.realpath( r ) 168 r = osp.normpath(r) 169 return r
170 171
172 -def homefile( filename, otherUser=1, ownCopy=1 ):
173 """ 174 Relativize a file name to ~ or, if it is in another user's home, 175 to ~otheruser or, if it is in nobody's home, to / . 176 177 L{splithome()} is used to also guess home directories of other users. 178 179 @param filename: name of file 180 @type filename: str 181 @param otherUser: look also in other user's home directories (default 1) 182 @type otherUser: 1|0 183 @param ownCopy: replace alien path by path into own home directory if 184 possible, e.g. ~other/data/x is replaced 185 by ~/data/x if there is such a file. (default 1) Careful! 186 @type ownCopy: 1|0 187 188 @return: path or filename 189 @rtype: str 190 """ 191 f = absfile( filename ) 192 my_home = osp.expanduser('~') 193 user_home, rest = splithome( f ) 194 195 if user_home == my_home: 196 return f.replace( user_home, '~', 1 ) 197 198 if otherUser and user_home != '': 199 ## first try to find same path in own home directory 200 if ownCopy: 201 my_path = os.path.join( my_home, rest ) 202 if osp.exists( my_path ): 203 return my_path 204 205 user = osp.split( user_home )[-1] 206 return f.replace( user_home+'/', '~' + user + '/', 1 ) 207 208 return f
209 210
211 -def splithome( filename ):
212 """ 213 Split path into home directory and remaining path. Valid home directories 214 are folders belonging to the same folder as the current user's home. I.e. 215 the method tries also to guess home directories of other users. 216 217 @param filename: name of file 218 @type filename: str 219 220 @return: home folder of some user, remaining path relative to home 221 @rtype: (str, str) 222 """ 223 home = osp.expanduser( '~' ) 224 home_base = osp.split( home )[0] 225 226 if filename.find( home_base ) != 0: 227 return '', filename 228 229 f = filename.replace( home_base + '/', '', 1 ) 230 user = f.split( '/' )[0] 231 232 user_home = os.path.join( home_base, user ) 233 rest = f.replace( user + '/', '', 1 ) 234 235 return user_home, rest
236 237
238 -def stripSuffix( filename ):
239 """ 240 Return file name without ending. 241 242 @param filename: name of file 243 @type filename: str 244 245 @return: filename or path without suffix 246 @rtype: str 247 """ 248 try: 249 if filename.find('.') <> -1: 250 filename = filename[: filename.rfind('.') ] # remove ending 251 except: 252 pass ## just in case there is no ending to start with... 253 254 return filename
255 256
257 -def stripFilename( filename ):
258 """ 259 Return filename without path and without ending. 260 261 @param filename: name of file 262 @type filename: str 263 264 @return: base filename 265 @rtype: str 266 """ 267 name = osp.basename( filename ) # remove path 268 try: 269 if name.find('.') <> -1: 270 name = name[: name.rfind('.') ] # remove ending 271 except: 272 pass ## just in case there is no ending to start with... 273 274 return name
275 276
277 -def fileLength( filename ):
278 """ 279 Count number of lines in a file. 280 281 @param filename: name of file 282 @type filename: str 283 284 @return: number of lines 285 @rtype: int 286 """ 287 p1 = subprocess.Popen( ['cat',filename], stdout=subprocess.PIPE ) 288 p2 = subprocess.Popen( ["wc", "-l"], stdin=p1.stdout, 289 stdout=subprocess.PIPE ) 290 return int(p2.communicate()[0])
291 292
293 -def tempDir():
294 """ 295 Get folder for temporary files - either from environment settings 296 or '/tmp' 297 298 @return: directort for temporary files 299 @rtype: str 300 """ 301 if tempfile.tempdir != None: 302 return tempfile.tempdir 303 304 return osp.dirname( tempfile.mktemp() )
305 306
307 -def file2dic( filename ):
308 """ 309 Construct dictionary from file with key - value pairs (one per line). 310 311 @param filename: name of file 312 @type filename: str 313 314 @raise ToolsError: if file can't be parsed into dictionary 315 @raise IOError: if file can't be opened 316 """ 317 try: 318 line = None 319 result = {} 320 for line in open( filename ): 321 322 if '#' in line: 323 line = line[ : line.index('#') ] 324 line = line.strip() 325 326 l = line.split()[1:] 327 328 if len( l ) == 0 and len( line ) > 0: 329 result[ line.split()[0] ] = '' 330 if len( l ) == 1: 331 result[ line.split()[0] ] = l[0] 332 if len( l ) > 1: 333 result[ line.split()[0] ] = l 334 except: 335 s = "Error parsing option file %s." % fname 336 s += '\nLine: ' + str( line ) 337 s += '\n' + lastError() 338 raise ToolsError( s ) 339 340 return result
341 342
343 -def get_cmdDict(lst_cmd, dic_default):
344 """ 345 Parse commandline options into dictionary of type C{ {<option> : <value>} } 346 Options are recognised by a leading '-'. 347 Error handling should be improved. 348 349 Option C{ -x |file_name| } is interpreted as file with additional options. 350 The key value pairs in lst_cmd replace key value pairs in the 351 -x file and in dic_default. 352 353 354 @param lst_cmd: list with the command line options:: 355 e.g. ['-pdb', 'in1.pdb', 'in2.pdb', '-o', 'out.dat'] 356 @type lst_cmd: [str] 357 @param dic_default: dictionary with default options:: 358 e.g. {'psf':'in.psf'} 359 @type dic_default: {str : str} 360 361 @return: command dictionary:: 362 ala {'pdb':['in1.pdb', 'in2.pdb'], 'psf':'in.psf', 'o':'out.dat'} 363 @rtype: {<option> : <value>} 364 """ 365 dic_cmd = {} # create return dictionary 366 try: 367 368 for cmd in lst_cmd: 369 if (cmd[0] == '-'): # this entry is new option 370 current_option = cmd[1:] # take all but leading "-" 371 dic_cmd[current_option] = "" # make sure key exists even 372 # w/o value 373 counter = 0 # number of values for this option 374 else: # this entry is value for latest option 375 376 if counter < 1: 377 dic_cmd[current_option] = cmd 378 379 # in case, several values follow after a "-xxx" option convert dictionary 380 # entry into list and add all elements (until the next "-") to this list 381 else: 382 if counter == 1: # there is already a value assigned 383 # convert to list 384 dic_cmd[current_option] = [dic_cmd[current_option]] 385 # add value to list 386 dic_cmd[current_option] = dic_cmd[current_option] + [cmd] 387 388 counter = counter + 1 389 390 except (KeyError, UnboundLocalError), why: 391 errWriteln("Can't resolve command line options.\n \tError:"+str(why)) 392 393 ## get extra options from external file 394 try: 395 if dic_cmd.has_key('x'): 396 d = file2dic( dic_cmd['x'] ) 397 d.update( dic_cmd ) 398 dic_cmd = d 399 except IOError: 400 errWriteln( "Error opening %s."% dic_cmd['x'] ) 401 except ToolsError, why: 402 errWriteln( str(why) ) 403 404 ## fill in missing default values 405 dic_default.update( dic_cmd ) 406 dic_cmd = dic_default 407 408 return dic_cmd
409 410
411 -def cmdDict( defaultDic={} ):
412 """ 413 Convenience implementation of L{get_cmdDict}. Take command line options 414 from sys.argv[1:] and convert them into dictionary. 415 Example:: 416 '-o out.dat -in 1.pdb 2.pdb 3.pdb -d' will be converted to 417 {'o':'out.dat', 'in': ['1.pdb', '2.pdb', '3.pdb'], 'd':'' } 418 419 Option C{ -x |file_name| } is interpreted as file with additional options. 420 421 @param defaultDic: dic with default values. 422 @type defaultDic: dic 423 424 @return: command dictionary 425 @rtype: dic 426 """ 427 return get_cmdDict( sys.argv[1:], defaultDic )
428 429
430 -def Dump(this, filename, gzip = 0, mode = 'w'):
431 """ 432 Dump this:: 433 Dump(this, filename, gzip = 0) 434 Supports also '~' or '~user'. 435 436 @author: Wolfgang Rieping 437 @note gzip currently doesn't work. 438 439 @param this: object to dump 440 @type this: any 441 @param filename: name of file 442 @type filename: str 443 @param gzip: gzip dumped object (default 0) 444 @type gzip: 1|0 445 @param mode: file handle mode (default w) 446 @type mode: str 447 """ 448 filename = osp.expanduser(filename) 449 450 if not mode in ['w', 'a']: 451 raise "mode has to be 'w' (write) or 'a' (append)" 452 453 ## if gzip: 454 ## import gzip 455 ## f = gzip.GzipFile(filename, mode) 456 ## else: 457 f = open(filename, mode) 458 459 cPickle.dump(this, f, 1) 460 461 f.close()
462 463
464 -def Load(filename, gzip = 0):
465 """ 466 Load dumped object from file. 467 468 @author: Wolfgang Rieping 469 470 @param filename: name of file 471 @type filename: str 472 @param gzip: unzip dumped object (default 0) 473 @type gzip: 1|0 474 475 @return: loaded object 476 @rtype: any 477 478 @raise cPickle.UnpicklingError, if the pickle format is not recognized 479 """ 480 filename = osp.expanduser(filename) 481 482 try: 483 f = open(filename) 484 485 objects = [] 486 487 eof = 0 488 n = 0 489 490 while not eof: 491 try: 492 this = cPickle.load(f) 493 objects.append(this) 494 n += 1 495 except EOFError: 496 eof = 1 497 498 f.close() 499 500 if n == 1: 501 return objects[0] 502 else: 503 return tuple(objects) 504 505 except ValueError, why: 506 raise PickleError, 'Python pickle %s is corrupted.' % filename
507 508 509 ## obsolete
510 -def getOnDemand( attr, dumpIt=1):
511 """ 512 Return attr either unpickled, freshly calculated or unchanged. 513 If attr is no tuple or anything else goes wrong it is returned unchanged 514 515 @param attr: tuple of string and function:: 516 attr[0] - name of existing or non-existing file or '' 517 attr[1] - function to get result if it can't be unpickled 518 @type attr: (str, function) 519 @param dumpIt: try pickling return value to attr[0](if valid file) 520 (default 1) 521 @type dumpIt: 0|1 522 523 @return: attr (unchanged or object unpickeled from file) 524 @rtype: (str, function) 525 """ 526 try: 527 if type( attr ) == type( ('','') ) and type( attr[0] ) == type( '' ): 528 529 fname = attr[0] 530 function = attr[1] 531 532 ## file exists, try unpickling from it 533 if type(fname)==type('') and osp.exists( attr[0] ): 534 return Load( fname ) 535 536 ## pretend function exists, try to calculate return value 537 result = function() 538 539 ## pickle result if file would end up in a valid path 540 if osp.exists( osp.dirname( fname )) and dumpIt: 541 Dump( result, fname ) 542 543 return result 544 545 except: 546 print lastError() 547 548 ## return attr directly if above failed 549 return attr
550 551
552 -def projectRoot():
553 """ 554 Root of biskit project. 555 556 @return: absolute path of the root of current project:: 557 i.e. '/home/Bis/raik/biskit' 558 @rtype: string 559 """ 560 ## import this module 561 from Biskit import tools 562 ## get location of this module 563 f = absfile(tools.__file__) 564 ## extract path and assume it is 'project_root/Biskit' 565 f = osp.split( f )[0] + '/../' 566 return absfile( f )
567 568
569 -def testRoot():
570 """ 571 Root of Biskit test directory. 572 573 @return: absolute path 574 @rtype: string 575 """ 576 return projectRoot() + '/test'
577 578
579 -def isBinary( f ):
580 """ 581 Check if file is a binary. 582 583 @param f: path to existing file 584 @type f: str 585 586 @return: condition 587 @rtype: 1|0 588 589 @raise OSError: if file doesn't exist 590 """ 591 st = os.stat( f ) 592 mode = st[0] ## permissions 593 mode = int( oct( mode & 0777 )[1] ) ## user permissions as octal value 594 595 return ( operator.and_( mode, 1 ) == 1 )
596 597
598 -def binExists( f ):
599 """ 600 Check if binary with file name f exists. 601 602 @param f: binary file name 603 @type f: str 604 605 @return: True if binary file f is found in PATH and is executable 606 @rtype: 1|0 607 """ 608 if osp.exists( f ): 609 return isBinary( f ) 610 611 for path in os.getenv( 'PATH' ).split(':') : 612 613 full_path = osp.join( path, f ) 614 615 if osp.exists( full_path ) and isBinary( full_path ): 616 return True 617 618 return False
619 620
621 -def absbinary( f ):
622 """ 623 Absolute path of binary. 624 625 @param f: binary file name 626 @type f: str 627 628 @return: full path to existing binary 629 @rtype: str 630 631 @raise IOError: if an executable binary is not found in PATH 632 """ 633 if osp.exists( f ) and isBinary( f ): 634 return f 635 636 for path in os.getenv( 'PATH' ).split(':') : 637 638 full_path = osp.join( path, f ) 639 640 if osp.exists( full_path ) and isBinary( full_path ): 641 return full_path 642 643 raise IOError, 'binary %s not found.' % f
644 645
646 -def platformFolder( f ):
647 """ 648 Get a platform-specific subfolder of f for platform-dependent imports. 649 650 @param f: parent folder 651 @type f: str 652 653 @return: path 654 @rtype: str 655 """ 656 import platform as P 657 658 __version = '.'.join( P.python_version().split('.')[:2] ) 659 660 r = 'py%s_%s' % (__version, P.machine() ) ## , P.architecture()[0] ) 661 662 r = os.path.join( f, r) 663 664 return r
665 666
667 -def sortString( s ):
668 """ 669 Sort the letters of a string:: 670 sortString( str ) -> str with sorted letters 671 672 @param s: string to be sorted 673 @type s: str 674 675 @return: sorted string 676 @rtype: str 677 """ 678 l = list(s) 679 l.sort() 680 return ''.join(l)
681 682
683 -def string2Fname( s ):
684 """ 685 Remove forbidden character from string so that it can be used as a 686 filename. 687 688 @param s: string 689 @type s: str 690 691 @return: cleaned string 692 @rtype: str 693 """ 694 forbidden = ['*', '?', '|', '/', ' '] 695 replaceme = ['-', '-', '-', '-', '_'] 696 for i in range(0, len(forbidden)): 697 s = s.replace( forbidden[i], replaceme[i] ) 698 return s
699 700
701 -def toIntList( o ):
702 """ 703 Convert single value or list of values into list of integers. 704 705 @param o: value or list 706 @type o: int or [int] 707 708 @return: list of integer 709 @rtype: [int] 710 """ 711 if type( o ) != type( [] ): 712 o = [ o ] 713 714 return map( int, o )
715 716
717 -def toIntArray( o ):
718 """ 719 Convert single value or list of values to Numeric array of int. 720 721 @param o: value or list 722 @type o: int or [int] 723 724 @return: array of integer 725 @rtype: Numeric.array('i') 726 """ 727 if type( o ) == list or type( o ) == type( Numeric.array([])): 728 return Numeric.array( map( int, o ) ) 729 730 return Numeric.array( [ int( o ) ] )
731 732
733 -def toList( o ):
734 """ 735 Make a list:: 736 toList(o) -> [o], or o, if o is already a list 737 738 @param o: value(s) 739 @type o: any or [any] 740 741 @return: list 742 @rtype: [any] 743 """ 744 if type( o ) != type( [] ): 745 return [ o ] 746 return o
747 748
749 -def toStr( o ):
750 """ 751 Make a string from a list or interger. 752 Stripping of any flanking witespaces. 753 754 @param o: value(s) 755 @type o: any or [any] 756 757 @return: list 758 @rtype: [any] 759 """ 760 if type( o ) == type( 1 ): 761 return str(o) 762 763 if type( o ) == type( [] ): 764 s = '' 765 for item in o: 766 s += string.strip( str(item) ) 767 return s 768 769 return o
770 771
772 -def toInt( o, default=None ):
773 """ 774 Convert to intereg if possible:: 775 toInt(o) -> int, int(o) or default if o is impossible to convert. 776 777 @param o: value 778 @type o: any 779 @param default: value to return if conversion is impossible (default: None) 780 @type default: any 781 782 @return: integer OR None 783 @rtype: int OR None 784 """ 785 if o == None or o == '': 786 return default 787 try: 788 return int( o ) 789 except: 790 return default
791 792
793 -def colorSpectrum( nColors, firstColor='FF0000', lastColor='FF00FF' ):
794 """ 795 Creates a list of 'nColors' colors for biggles starting at 796 'firstColor' ending at 'lastColor' 797 Examples:: 798 free spectrum red FF0000 to green 00FF00 799 bound spectrum cyan 00FFFF to magenta FF00FF 800 801 @param nColors: number of colors to create 802 @type nColors: int 803 @param firstColor: first color in hex format (default: FF0000) 804 @type firstColor: str 805 @param lastColor: last color in hex format (default: FF00FF) 806 @type lastColor: str 807 808 @return: list of colors 809 @rtype: [int] 810 """ 811 spec = [] 812 out = os.popen( projectRoot() + '/external/spectrum.pl ' +str(nColors) + 813 ' ' + str(firstColor) + ' ' + str(lastColor) ).readlines() 814 815 for s in out: 816 spec += [ int( float( '0x' + str( string.strip( s ) ) ) ) ] 817 818 return spec
819 820
821 -def hexColors( nColors, firstColor='FF0000', lastColor='FF00FF' ):
822 """ 823 Creates a list of 'nColors' colors for PyMol starting at 824 'firstColor' ending at 'lastColor' 825 Examples:: 826 free spectrum red FF0000 to green 00FF00 827 bound spectrum cyan 00FFFF to magenta FF00FF 828 829 @param nColors: number of colors to create 830 @type nColors: int 831 @param firstColor: first color in hex format (default: FF0000) 832 @type firstColor: str 833 @param lastColor: last color in hex format (default: FF00FF) 834 @type lastColor: str 835 836 @return: list of hex colors 837 @rtype: [ str ] 838 """ 839 spec = [] 840 out = os.popen( projectRoot() + '/external/spectrum.pl ' +str(nColors) + 841 ' ' + str(firstColor) + ' ' + str(lastColor) ).readlines() 842 843 for s in out: 844 spec += [ '0x' + str( string.strip( s ) ) ] 845 846 return spec
847 848
849 -def rgb2hex( rgbColor ):
850 """ 851 convert rgb color into 8 bit hex rgb color:: 852 [ 1.0, 0.0, 1.0, ] -> 'FF00FF' 853 854 @param rgbColor: RGB-color e.g. [ 1.0, 0.0, 1.0, ] 855 @type rgbColor : [float] 856 857 @return: hex colors 858 @rtype: str 859 """ 860 hexRgb = '' 861 for i in range(0,3): 862 component = hex( int( rgbColor[i]*255 ) )[2:] 863 864 if len(component) == 1: 865 hexRgb += '0' + component 866 else: 867 hexRgb += component 868 869 return hexRgb
870 871
872 -def hex2rgb( hexColor, str=0 ):
873 """ 874 convert 8 bit hex rgb color into rgb color :: 875 'FF00FF' -> [ 1.0, 0.0, 1.0, ] 876 877 @param hexColor: HEX-color e.g. 'FF00FF' 878 @type hexColor: str 879 @param str: return rgb colors as a tring (i.e for PyMol) 880 @type str: 1|0 881 882 @return: rgb colors 883 @rtype: [float] 884 """ 885 rgb = [] 886 if hexColor[:2] == '0x': 887 hexColor = hexColor[2:] 888 889 for i in range(0,6,2): 890 rgb += [ int(hexColor[i:i+2], 16)/255.0 ] 891 892 if str: 893 rgb_str= '[ %.3f, %.3f, %.3f ]'%(rgb[0], rgb[1], rgb[2]) 894 895 return rgb_str 896 897 return rgb
898 899
900 -def dateString():
901 """ 902 @return: DD/MM/YYYY 903 @rtype: str 904 """ 905 t = localtime() 906 return '%02i/%02i/%i' % (t[2],t[1],t[0] )
907 908
909 -def dateSortString():
910 """ 911 @return: YYYY/MM/DD:hh:mm.ss.ms 912 @rtype: 913 """ 914 t = localtime() 915 return "%i/%02i/%02i:%02i.%02i.%02i" % (t[0],t[1],t[2],t[3],t[4],t[5])
916 917
918 -def tryRemove(f, verbose=0, tree=0, wildcard=0 ):
919 """ 920 Remove file or folder:: 921 remove(f [,verbose=0, tree=0]), remove if possible, otherwise do nothing 922 923 @param f: file path 924 @type f: str 925 @param verbose: report failure (default 0) 926 @type verbose: 0|1 927 @param tree: remove whole folder (default 0) 928 @type tree: 0|1 929 @param wildcard: filename contains wildcards (default 0) 930 @type wildcard: 0|1 931 932 @return: 1 if file was removed 933 @rtype: 1|0 934 """ 935 try: 936 if osp.isdir(f): 937 if tree: 938 shutil.rmtree( f, ignore_errors=1 ) 939 else: 940 errWriteln('%s is directory - not removed.') 941 else: 942 if wildcard: 943 l = glob.glob( f ) 944 for i in l: 945 os.remove( i ) 946 else: 947 os.remove( f ) 948 return 1 949 except: 950 if verbose: errWriteln( 'Warning: Cannot remove %s.' % str(f) ) 951 return 0
952
953 -def backup( fname, suffix='~' ):
954 """ 955 Create backup of file if it already exists. 956 @param fname: file name 957 @type fname: str 958 @param suffix: suffix to add to backup file name ['~'] 959 @type suffix: str 960 961 @return: True if backup was created, False otherwise 962 @rtype: bool 963 """ 964 fname = absfile( fname ) 965 966 if os.path.exists( fname ): 967 os.rename( fname, fname + '~' ) 968 return True 969 return False
970 971
972 -def ensure( v, t, allowed=[], forbidden=[] ):
973 """ 974 Check type of a variable 975 976 @param v: variable to test 977 @type v: variable 978 @param t: required type 979 @type t: str 980 @param allowed: list of additional values allowed for v {default: []} 981 @type allowed: [str] 982 983 @raise TypeError: if invalid 984 """ 985 if allowed: 986 allowed = toList( allowed ) 987 if len( allowed ) > 0 and v in allowed: 988 return 989 990 if not isinstance(v, t): 991 raise TypeError, 'looked for %s but found %s' % (str(t),str(v)[:20]) 992 993 if forbidden and v in forbidden: 994 raise TypeError, 'value %s is not allowed.' % (str(v)[:20])
995 996
997 -def clipStr( s, length, suffix='..', expandtabs=1 ):
998 """ 999 Shorten string from end and replace the last characters with suffix:: 1000 clipStr( str, length ) -> str, with len( str ) <= length 1001 1002 @param s: original string 1003 @type s: str 1004 @param length: desired length 1005 @type length: int 1006 @param suffix: suffix (default: ..) 1007 @type suffix: str 1008 1009 @return: shortend string 1010 @rtype: str 1011 """ 1012 if expandtabs: 1013 s = s.expandtabs() 1014 1015 if len(s) > length: 1016 s = s[:(length - len(suffix))] + suffix 1017 return s
1018 1019
1020 -def info( item, short=1 ):
1021 """ 1022 :: 1023 info( item, short=1) -> Print useful information about item. 1024 1025 @param item: query item 1026 @type item: item 1027 @param short: short version (default: 1) 1028 @type short: 1|0 1029 """ 1030 ## quick and dirty ## 1031 if hasattr(item, '__name__'): 1032 print "NAME: ", item.__name__ 1033 if hasattr(item, '__class__'): 1034 print "CLASS: ", item.__class__.__name__ 1035 print "ID: ", id(item) 1036 print "TYPE: ", type(item) 1037 print "VALUE: ", repr(item) 1038 print "CALLABLE:", 1039 if callable(item): 1040 print "Yes" 1041 else: 1042 print "No" 1043 if hasattr(item, '__doc__'): 1044 doc = getattr(item, '__doc__') 1045 if doc: 1046 doc = doc.strip() # Remove leading/trailing whitespace. 1047 if short: 1048 doc = doc.split('\n')[0] 1049 print "DOC: ", '\n\t' * (not short), doc 1050 1051 print "\nMETHODS" 1052 methods = [ getattr( item, m ) for m in dir( item ) 1053 if callable( getattr( item, m ) ) ] 1054 1055 for m in methods: 1056 doc = getattr(m, '__doc__', '') 1057 if doc: 1058 doc = str(doc).strip() 1059 if short: 1060 doc = str(doc).split('\n')[0] 1061 else: 1062 doc = '' 1063 s = "%-15s: " % (getattr(m,'__name__','?')) + '\n\t'*(not short) + doc 1064 if short: 1065 s = clipStr( s, 79 ) 1066 print s 1067 1068 if hasattr( item, '__dict__'): 1069 1070 print "\nFIELDS" 1071 for k, v in item.__dict__.items(): 1072 s = "%-15s: %s" % (k, str(v).strip() ) 1073 print clipStr( s, 79 )
1074 1075
1076 -class PseudoClass(object):
1077 """ 1078 Empty class that raises an ImportError upon creation. 1079 """
1080 - def __new__(cls, *args, **kw):
1081 raise ImportError, \ 1082 'Class %r is not available because of missing modules: %r' \ 1083 % (cls.__name__, str(cls.error))
1084 1085 import new 1086
1087 -def tryImport( module, cls, as=None, namespace=None ):
1088 """ 1089 Try to import a class from a module. If that fails, 'import' a 1090 default class of the same name that raises an exception when used. 1091 1092 @param module: name of the module 1093 @type module: str 1094 @param cls : name of the class 1095 @type cls : str 1096 @param namespace: namespace for the import [default: globals() ] 1097 @type namespace: dict 1098 1099 @return: True if import succeeded, False otherwise 1100 @rtype: bool 1101 """ 1102 as = as or cls 1103 g = namespace or globals() 1104 try: 1105 exec 'from %s import %s as %s' % (module, cls, as) in g 1106 return True 1107 1108 except ImportError, e: 1109 1110 Cls = new.classobj( cls,(PseudoClass,),{'error':e} ) 1111 g.update( {as: Cls} ) 1112 1113 return False
1114
1115 -def tryImportModule( module, as=None, namespace=None ):
1116 """ 1117 Try to import a class from a module. If that fails, 'import' a 1118 default class of the same name that raises an exception when used. 1119 1120 @param module: name of the module 1121 @type module: str 1122 @param namespace: namespace for the import [default: globals() ] 1123 @type namespace: dict 1124 1125 @return: True if import succeeded, False otherwise 1126 @rtype: bool 1127 """ 1128 as = as or module 1129 g = namespace or globals() 1130 try: 1131 exec 'import %s as %s' % (module, as) in g 1132 return True 1133 1134 except ImportError, e: 1135 1136 m = new.module( as, doc='Pseudo module. Import of real one failed.' ) 1137 m.error = str(e) 1138 1139 g.update( {as: m} ) 1140 1141 return False
1142 1143 1144 ############# 1145 ## TESTING 1146 ############# 1147
1148 -class Test:
1149 """ 1150 Test class 1151 """ 1152
1153 - def run( self, local=0 ):
1154 """ 1155 run function test 1156 1157 @param local: transfer local variables to global and perform 1158 other tasks only when run locally 1159 @type local: 1|0 1160 1161 @return: 1 1162 @rtype: int 1163 """ 1164 from Biskit import PDBModel 1165 1166 m = PDBModel( testRoot()+'/rec/1A2P.pdb') 1167 1168 if local: 1169 print "\nTEST info:" 1170 info(m) 1171 1172 if local: 1173 print "\nTEST Exception:" 1174 try: 1175 i = 1/0 1176 except: 1177 print lastErrorTrace() 1178 1179 if local: print "\nTEST ensure" 1180 ensure( m, PDBModel ) 1181 1182 if local: 1183 globals().update( locals() ) 1184 1185 absfile('~') 1186 1187 return 1
1188 1189
1190 - def expected_result( self ):
1191 """ 1192 Precalculated result to check for consistent performance. 1193 1194 @return: 1 1195 @rtype: int 1196 """ 1197 return 1
1198 1199 1200 1201 if __name__ == '__main__': 1202 1203 test = Test() 1204 1205 assert test.run( local=1 ) == test.expected_result() 1206