Package madgraph :: Package various :: Module misc
[hide private]
[frames] | no frames]

Source Code for Module madgraph.various.misc

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2009 The MadGraph5_aMC@NLO Development team and Contributors 
   4  # 
   5  # This file is a part of the MadGraph5_aMC@NLO project, an application which  
   6  # automatically generates Feynman diagrams and matrix elements for arbitrary 
   7  # high-energy processes in the Standard Model and beyond. 
   8  # 
   9  # It is subject to the MadGraph5_aMC@NLO license which should accompany this  
  10  # distribution. 
  11  # 
  12  # For more information, visit madgraph.phys.ucl.ac.be and amcatnlo.web.cern.ch 
  13  # 
  14  ################################################################################ 
  15   
  16  """A set of functions performing routine administrative I/O tasks.""" 
  17   
  18  import logging 
  19  import os 
  20  import re 
  21  import signal 
  22  import subprocess 
  23  import sys 
  24  import StringIO 
  25  import sys 
  26  import optparse 
  27  import time 
  28  import shutil 
  29  import gzip as ziplib 
  30   
  31  try: 
  32      # Use in MadGraph 
  33      import madgraph 
  34      from madgraph import MadGraph5Error, InvalidCmd 
  35      import madgraph.iolibs.files as files 
  36  except Exception, error: 
  37      if __debug__: 
  38          print error 
  39      # Use in MadEvent 
  40      import internal as madgraph 
  41      from internal import MadGraph5Error, InvalidCmd 
  42      import internal.files as files 
  43       
  44  logger = logging.getLogger('cmdprint.ext_program') 
  45  logger_stderr = logging.getLogger('madevent.misc') 
  46  pjoin = os.path.join 
47 48 #=============================================================================== 49 # parse_info_str 50 #=============================================================================== 51 -def parse_info_str(fsock):
52 """Parse a newline separated list of "param=value" as a dictionnary 53 """ 54 55 info_dict = {} 56 pattern = re.compile("(?P<name>\w*)\s*=\s*(?P<value>.*)", 57 re.IGNORECASE | re.VERBOSE) 58 for entry in fsock: 59 entry = entry.strip() 60 if len(entry) == 0: continue 61 m = pattern.match(entry) 62 if m is not None: 63 info_dict[m.group('name')] = m.group('value') 64 else: 65 raise IOError, "String %s is not a valid info string" % entry 66 67 return info_dict
68
69 70 #=============================================================================== 71 # mute_logger (designed to be a decorator) 72 #=============================================================================== 73 -def mute_logger(names=['madgraph','ALOHA','cmdprint','madevent'], levels=[50,50,50,50]):
74 """change the logger level and restore those at their initial value at the 75 end of the function decorated.""" 76 def control_logger(f): 77 def restore_old_levels(names, levels): 78 for name, level in zip(names, levels): 79 log_module = logging.getLogger(name) 80 log_module.setLevel(level)
81 82 def f_with_no_logger(self, *args, **opt): 83 old_levels = [] 84 for name, level in zip(names, levels): 85 log_module = logging.getLogger(name) 86 old_levels.append(log_module.level) 87 log_module.setLevel(level) 88 try: 89 out = f(self, *args, **opt) 90 restore_old_levels(names, old_levels) 91 return out 92 except: 93 restore_old_levels(names, old_levels) 94 raise 95 96 return f_with_no_logger 97 return control_logger 98
99 #=============================================================================== 100 # get_pkg_info 101 #=============================================================================== 102 -def get_pkg_info(info_str=None):
103 """Returns the current version information of the MadGraph5_aMC@NLO package, 104 as written in the VERSION text file. If the file cannot be found, 105 a dictionary with empty values is returned. As an option, an info 106 string can be passed to be read instead of the file content. 107 """ 108 109 if info_str is None: 110 info_dict = files.read_from_file(os.path.join(madgraph.__path__[0], 111 "VERSION"), 112 parse_info_str, 113 print_error=False) 114 else: 115 info_dict = parse_info_str(StringIO.StringIO(info_str)) 116 117 return info_dict
118
119 #=============================================================================== 120 # get_time_info 121 #=============================================================================== 122 -def get_time_info():
123 """Returns the present time info for use in MG5 command history header. 124 """ 125 126 creation_time = time.asctime() 127 time_info = {'time': creation_time, 128 'fill': ' ' * (26 - len(creation_time))} 129 130 return time_info
131
132 #=============================================================================== 133 # Find the subdirectory which includes the files ending with a given extension 134 #=============================================================================== 135 -def find_includes_path(start_path, extension):
136 """Browse the subdirectories of the path 'start_path' and returns the first 137 one found which contains at least one file ending with the string extension 138 given in argument.""" 139 140 subdirs=[pjoin(start_path,dir) for dir in os.listdir(start_path)] 141 for subdir in subdirs: 142 if os.path.isfile(subdir): 143 if os.path.basename(subdir).endswith(extension): 144 return start_path 145 elif os.path.isdir(subdir): 146 return find_includes_path(subdir, extension) 147 return None
148
149 #=============================================================================== 150 # find a executable 151 #=============================================================================== 152 -def which(program):
153 def is_exe(fpath): 154 return os.path.exists(fpath) and os.access(\ 155 os.path.realpath(fpath), os.X_OK)
156 157 if not program: 158 return None 159 160 fpath, fname = os.path.split(program) 161 if fpath: 162 if is_exe(program): 163 return program 164 else: 165 for path in os.environ["PATH"].split(os.pathsep): 166 exe_file = os.path.join(path, program) 167 if is_exe(exe_file): 168 return exe_file 169 return None 170
171 #=============================================================================== 172 # find a library 173 #=============================================================================== 174 -def which_lib(lib):
175 def is_lib(fpath): 176 return os.path.exists(fpath) and os.access(fpath, os.R_OK)
177 178 if not lib: 179 return None 180 181 fpath, fname = os.path.split(lib) 182 if fpath: 183 if is_lib(lib): 184 return lib 185 else: 186 locations = sum([os.environ[env_path].split(os.pathsep) for env_path in 187 ["DYLD_LIBRARY_PATH","LD_LIBRARY_PATH","LIBRARY_PATH","PATH"] 188 if env_path in os.environ],[]) 189 for path in locations: 190 lib_file = os.path.join(path, lib) 191 if is_lib(lib_file): 192 return lib_file 193 return None 194
195 #=============================================================================== 196 # Return Nice display for a random variable 197 #=============================================================================== 198 -def nice_representation(var, nb_space=0):
199 """ Return nice information on the current variable """ 200 201 #check which data to put: 202 info = [('type',type(var)),('str', var)] 203 if hasattr(var, 'func_doc'): 204 info.append( ('DOC', var.func_doc) ) 205 if hasattr(var, '__doc__'): 206 info.append( ('DOC', var.__doc__) ) 207 if hasattr(var, '__dict__'): 208 info.append( ('ATTRIBUTE', var.__dict__.keys() )) 209 210 spaces = ' ' * nb_space 211 212 outstr='' 213 for name, value in info: 214 outstr += '%s%3s : %s\n' % (spaces,name, value) 215 216 return outstr
217 218 # 219 # Decorator for re-running a crashing function automatically. 220 # 221 wait_once = False
222 -def multiple_try(nb_try=5, sleep=20):
223 224 def deco_retry(f): 225 def deco_f_retry(*args, **opt): 226 for i in range(nb_try): 227 try: 228 return f(*args, **opt) 229 except KeyboardInterrupt: 230 raise 231 except Exception, error: 232 global wait_once 233 if not wait_once: 234 text = """Start waiting for update. (more info in debug mode)""" 235 logger.info(text) 236 logger_stderr.debug('fail to do %s function with %s args. %s try on a max of %s (%s waiting time)' % 237 (str(f), ', '.join([str(a) for a in args]), i+1, nb_try, sleep * (i+1))) 238 logger_stderr.debug('error is %s' % str(error)) 239 wait_once = True 240 time.sleep(sleep * (i+1)) 241 242 raise error.__class__, '[Fail %i times] \n %s ' % (i+1, error)
243 return deco_f_retry 244 return deco_retry 245
246 #=============================================================================== 247 # Compiler which returns smart output error in case of trouble 248 #=============================================================================== 249 -def compile(arg=[], cwd=None, mode='fortran', job_specs = True, nb_core=1 ,**opt):
250 """compile a given directory""" 251 252 cmd = ['make'] 253 try: 254 if nb_core > 1: 255 cmd.append('-j%s' % nb_core) 256 cmd += arg 257 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, 258 stderr=subprocess.STDOUT, cwd=cwd, **opt) 259 (out, err) = p.communicate() 260 except OSError, error: 261 if cwd and not os.path.exists(cwd): 262 raise OSError, 'Directory %s doesn\'t exists. Impossible to run make' % cwd 263 else: 264 error_text = "Impossible to compile %s directory\n" % cwd 265 error_text += "Trying to launch make command returns:\n" 266 error_text += " " + str(error) + "\n" 267 error_text += "In general this means that your computer is not able to compile." 268 if sys.platform == "darwin": 269 error_text += "Note that MacOSX doesn\'t have gmake/gfortan install by default.\n" 270 error_text += "Xcode3 contains those required programs" 271 raise MadGraph5Error, error_text 272 273 if p.returncode: 274 # Check that makefile exists 275 if not cwd: 276 cwd = os.getcwd() 277 all_file = [f.lower() for f in os.listdir(cwd)] 278 if 'makefile' not in all_file: 279 raise OSError, 'no makefile present in %s' % os.path.realpath(cwd) 280 281 if mode == 'fortran' and not (which('g77') or which('gfortran')): 282 error_msg = 'A fortran compiler (g77 or gfortran) is required to create this output.\n' 283 error_msg += 'Please install g77 or gfortran on your computer and retry.' 284 raise MadGraph5Error, error_msg 285 elif mode == 'cpp' and not which('g++'): 286 error_msg ='A C++ compiler (g++) is required to create this output.\n' 287 error_msg += 'Please install g++ (which is part of the gcc package) on your computer and retry.' 288 raise MadGraph5Error, error_msg 289 290 # Check if this is due to the need of gfortran 4.6 for quadruple precision 291 if any(tag.upper() in out.upper() for tag in ['real(kind=16)','real*16', 292 'complex*32']) and mode == 'fortran' and not \ 293 ''.join(get_gfortran_version().split('.')) >= '46': 294 if not which('gfortran'): 295 raise MadGraph5Error, 'The fortran compiler gfortran v4.6 or later '+\ 296 'is required to compile %s.\nPlease install it and retry.'%cwd 297 else: 298 logger_stderr.error('ERROR, you could not compile %s because'%cwd+\ 299 ' your version of gfortran is older than 4.6. MadGraph5_aMC@NLO will carry on,'+\ 300 ' but will not be able to compile an executable.') 301 return p.returncode 302 # Other reason 303 error_text = 'A compilation Error occurs ' 304 if cwd: 305 error_text += 'when trying to compile %s.\n' % cwd 306 error_text += 'The compilation fails with the following output message:\n' 307 error_text += ' '+out.replace('\n','\n ')+'\n' 308 error_text += 'Please try to fix this compilations issue and retry.\n' 309 error_text += 'Help might be found at https://answers.launchpad.net/madgraph5.\n' 310 error_text += 'If you think that this is a bug, you can report this at https://bugs.launchpad.net/madgraph5' 311 raise MadGraph5Error, error_text 312 return p.returncode
313
314 -def get_gfortran_version(compiler='gfortran'):
315 """ Returns the gfortran version as a string. 316 Returns '0' if it failed.""" 317 try: 318 p = Popen([compiler, '-dumpversion'], stdout=subprocess.PIPE, 319 stderr=subprocess.PIPE) 320 output, error = p.communicate() 321 version_finder=re.compile(r"(?P<version>(\d.)*\d)") 322 version = version_finder.search(output).group('version') 323 return version 324 except Exception: 325 return '0'
326
327 -def mod_compilator(directory, new='gfortran', current=None, compiler_type='gfortran'):
328 #define global regular expression 329 if type(directory)!=list: 330 directory=[directory] 331 332 #search file 333 file_to_change=find_makefile_in_dir(directory) 334 if compiler_type == 'gfortran': 335 comp_re = re.compile('^(\s*)FC\s*=\s*(.+)\s*$') 336 var = 'FC' 337 elif compiler_type == 'cpp': 338 comp_re = re.compile('^(\s*)CXX\s*=\s*(.+)\s*$') 339 var = 'CXX' 340 else: 341 MadGraph5Error, 'Unknown compiler type: %s' % compiler_type 342 343 mod = False 344 for name in file_to_change: 345 lines = open(name,'r').read().split('\n') 346 for iline, line in enumerate(lines): 347 result = comp_re.match(line) 348 if result: 349 if new != result.group(2): 350 mod = True 351 lines[iline] = result.group(1) + var + "=" + new 352 if mod: 353 open(name,'w').write('\n'.join(lines))
354
355 #=============================================================================== 356 # mute_logger (designed to work as with statement) 357 #=============================================================================== 358 -class MuteLogger(object):
359 """mute_logger (designed to work as with statement), 360 files allow to redirect the output of the log to a given file. 361 """ 362
363 - def __init__(self, names, levels, files=None, **opt):
364 assert isinstance(names, list) 365 assert isinstance(names, list) 366 367 self.names = names 368 self.levels = levels 369 if isinstance(files, list): 370 self.files = files 371 else: 372 self.files = [files] * len(names) 373 self.logger_saved_info = {} 374 self.opts = opt
375
376 - def __enter__(self):
377 old_levels = [] 378 for name, level, path in zip(self.names, self.levels, self.files): 379 if path: 380 self.setup_logFile_for_logger(path, name, **self.opts) 381 log_module = logging.getLogger(name) 382 old_levels.append(log_module.level) 383 log_module = logging.getLogger(name) 384 log_module.setLevel(level) 385 self.levels = old_levels
386
387 - def __exit__(self, ctype, value, traceback ):
388 for name, level, path, level in zip(self.names, self.levels, self.files, self.levels): 389 if 'keep' in self.opts and not self.opts['keep']: 390 self.restore_logFile_for_logger(name, level, path=path) 391 else: 392 self.restore_logFile_for_logger(name, level) 393 394 log_module = logging.getLogger(name) 395 log_module.setLevel(level)
396
397 - def setup_logFile_for_logger(self, path, full_logname, **opts):
398 """ Setup the logger by redirecting them all to logfiles in tmp """ 399 400 logs = full_logname.split('.') 401 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\ 402 range(len(full_logname.split('.')))] 403 for logname in lognames: 404 try: 405 os.remove(path) 406 except Exception, error: 407 pass 408 my_logger = logging.getLogger(logname) 409 hdlr = logging.FileHandler(path) 410 # I assume below that the orders of the handlers in my_logger.handlers 411 # remains the same after having added/removed the FileHandler 412 self.logger_saved_info[logname] = [hdlr, my_logger.handlers] 413 #for h in my_logger.handlers: 414 # h.setLevel(logging.CRITICAL) 415 for old_hdlr in list(my_logger.handlers): 416 my_logger.removeHandler(old_hdlr) 417 my_logger.addHandler(hdlr) 418 #my_logger.setLevel(level) 419 my_logger.debug('Log of %s' % logname)
420
421 - def restore_logFile_for_logger(self, full_logname, level, path=None, **opts):
422 """ Setup the logger by redirecting them all to logfiles in tmp """ 423 424 logs = full_logname.split('.') 425 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\ 426 range(len(full_logname.split('.')))] 427 for logname in lognames: 428 if path: 429 try: 430 os.remove(path) 431 except Exception, error: 432 pass 433 my_logger = logging.getLogger(logname) 434 if logname in self.logger_saved_info: 435 my_logger.removeHandler(self.logger_saved_info[logname][0]) 436 for old_hdlr in self.logger_saved_info[logname][1]: 437 my_logger.addHandler(old_hdlr) 438 else: 439 my_logger.setLevel(level)
440
441 #for i, h in enumerate(my_logger.handlers): 442 # h.setLevel(cls.logger_saved_info[logname][2][i]) 443 444 445 -def detect_current_compiler(path, compiler_type='fortran'):
446 """find the current compiler for the current directory""" 447 448 # comp = re.compile("^\s*FC\s*=\s*(\w+)\s*") 449 # The regular expression below allows for compiler definition with absolute path 450 if compiler_type == 'fortran': 451 comp = re.compile("^\s*FC\s*=\s*([\w\/\\.\-]+)\s*") 452 elif compiler_type == 'cpp': 453 comp = re.compile("^\s*CXX\s*=\s*([\w\/\\.\-]+)\s*") 454 else: 455 MadGraph5Error, 'Unknown compiler type: %s' % compiler_type 456 457 for line in open(path): 458 if comp.search(line): 459 compiler = comp.search(line).groups()[0] 460 return compiler
461
462 -def find_makefile_in_dir(directory):
463 """ return a list of all file starting with makefile in the given directory""" 464 465 out=[] 466 #list mode 467 if type(directory)==list: 468 for name in directory: 469 out+=find_makefile_in_dir(name) 470 return out 471 472 #single mode 473 for name in os.listdir(directory): 474 if os.path.isdir(directory+'/'+name): 475 out+=find_makefile_in_dir(directory+'/'+name) 476 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('makefile'): 477 out.append(directory+'/'+name) 478 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('make_opt'): 479 out.append(directory+'/'+name) 480 return out
481
482 -def rm_old_compile_file():
483 484 # remove all the .o files 485 os.path.walk('.', rm_file_extension, '.o') 486 487 # remove related libraries 488 libraries = ['libblocks.a', 'libgeneric_mw.a', 'libMWPS.a', 'libtools.a', 'libdhelas3.a', 489 'libdsample.a', 'libgeneric.a', 'libmodel.a', 'libpdf.a', 'libdhelas3.so', 'libTF.a', 490 'libdsample.so', 'libgeneric.so', 'libmodel.so', 'libpdf.so'] 491 lib_pos='./lib' 492 [os.remove(os.path.join(lib_pos, lib)) for lib in libraries \ 493 if os.path.exists(os.path.join(lib_pos, lib))]
494
495 496 -def rm_file_extension( ext, dirname, names):
497 498 [os.remove(os.path.join(dirname, name)) for name in names if name.endswith(ext)]
499
500 501 502 -def multiple_replacer(*key_values):
503 replace_dict = dict(key_values) 504 replacement_function = lambda match: replace_dict[match.group(0)] 505 pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M) 506 return lambda string: pattern.sub(replacement_function, string)
507
508 -def multiple_replace(string, *key_values):
509 return multiple_replacer(*key_values)(string)
510
511 # Control 512 -def check_system_error(value=1):
513 def deco_check(f): 514 def deco_f(arg, *args, **opt): 515 try: 516 return f(arg, *args, **opt) 517 except OSError, error: 518 logger.debug('try to recover from %s' % error) 519 if isinstance(arg, list): 520 prog = arg[0] 521 else: 522 prog = arg[0] 523 524 # Permission denied 525 if error.errno == 13: 526 if os.path.exists(prog): 527 os.system('chmod +x %s' % prog) 528 elif 'cwd' in opt and opt['cwd'] and \ 529 os.path.isfile(pjoin(opt['cwd'],arg[0])): 530 os.system('chmod +x %s' % pjoin(opt['cwd'],arg[0])) 531 return f(arg, *args, **opt) 532 # NO such file or directory 533 elif error.errno == 2: 534 # raise a more meaningfull error message 535 raise Exception, '%s fails with no such file or directory' \ 536 % arg 537 else: 538 raise
539 return deco_f 540 return deco_check 541
542 543 @check_system_error() 544 -def call(arg, *args, **opt):
545 """nice way to call an external program with nice error treatment""" 546 return subprocess.call(arg, *args, **opt)
547
548 @check_system_error() 549 -def Popen(arg, *args, **opt):
550 """nice way to call an external program with nice error treatment""" 551 return subprocess.Popen(arg, *args, **opt)
552
553 @multiple_try() 554 -def mult_try_open(filepath, *args, **opt):
555 """try to open a file with multiple try to ensure that filesystem is sync""" 556 return open(filepath, *args, ** opt)
557
558 559 ################################################################################ 560 # TAIL FUNCTION 561 ################################################################################ 562 -def tail(f, n, offset=None):
563 """Reads a n lines from f with an offset of offset lines. The return 564 value is a tuple in the form ``lines``. 565 """ 566 avg_line_length = 74 567 to_read = n + (offset or 0) 568 569 while 1: 570 try: 571 f.seek(-(avg_line_length * to_read), 2) 572 except IOError: 573 # woops. apparently file is smaller than what we want 574 # to step back, go to the beginning instead 575 f.seek(0) 576 pos = f.tell() 577 lines = f.read().splitlines() 578 if len(lines) >= to_read or pos == 0: 579 return lines[-to_read:offset and -offset or None] 580 avg_line_length *= 1.3 581 avg_line_length = int(avg_line_length)
582
583 ################################################################################ 584 # LAST LINE FUNCTION 585 ################################################################################ 586 -def get_last_line(fsock):
587 """return the last line of a file""" 588 589 return tail(fsock, 1)[0]
590
591 -class BackRead(file):
592 """read a file returning the lines in reverse order for each call of readline() 593 This actually just reads blocks (4096 bytes by default) of data from the end of 594 the file and returns last line in an internal buffer.""" 595 596
597 - def readline(self):
598 """ readline in a backward way """ 599 600 while len(self.data) == 1 and ((self.blkcount * self.blksize) < self.size): 601 self.blkcount = self.blkcount + 1 602 line = self.data[0] 603 try: 604 self.seek(-self.blksize * self.blkcount, 2) # read from end of file 605 self.data = (self.read(self.blksize) + line).split('\n') 606 except IOError: # can't seek before the beginning of the file 607 self.seek(0) 608 data = self.read(self.size - (self.blksize * (self.blkcount-1))) + line 609 self.data = data.split('\n') 610 611 if len(self.data) == 0: 612 return "" 613 614 line = self.data.pop() 615 return line + '\n'
616
617 - def __init__(self, filepos, blksize=4096):
618 """initialize the internal structures""" 619 620 # get the file size 621 self.size = os.stat(filepos)[6] 622 # how big of a block to read from the file... 623 self.blksize = blksize 624 # how many blocks we've read 625 self.blkcount = 1 626 file.__init__(self, filepos, 'rb') 627 # if the file is smaller than the blocksize, read a block, 628 # otherwise, read the whole thing... 629 if self.size > self.blksize: 630 self.seek(-self.blksize * self.blkcount, 2) # read from end of file 631 self.data = self.read(self.blksize).split('\n') 632 # strip the last item if it's empty... a byproduct of the last line having 633 # a newline at the end of it 634 if not self.data[-1]: 635 self.data.pop()
636
637 - def next(self):
638 line = self.readline() 639 if line: 640 return line 641 else: 642 raise StopIteration
643
644 645 -def write_PS_input(filePath, PS):
646 """ Write out in file filePath the PS point to be read by the MadLoop.""" 647 try: 648 PSfile = open(filePath, 'w') 649 # Add a newline in the end as the implementation fortran 'read' 650 # command on some OS is problematic if it ends directly with the 651 # floating point number read. 652 653 PSfile.write('\n'.join([' '.join(['%.16E'%pi for pi in p]) \ 654 for p in PS])+'\n') 655 PSfile.close() 656 except Exception: 657 raise MadGraph5Error, 'Could not write out the PS point to file %s.'\ 658 %str(filePath)
659
660 -def format_timer(running_time):
661 """ return a nicely string representing the time elapsed.""" 662 if running_time < 2e-2: 663 running_time = running_time = 'current time: %02dh%02d' % (time.localtime().tm_hour, time.localtime().tm_min) 664 elif running_time < 10: 665 running_time = ' %.2gs ' % running_time 666 elif 60 > running_time >= 10: 667 running_time = ' %.3gs ' % running_time 668 elif 3600 > running_time >= 60: 669 running_time = ' %im %is ' % (running_time // 60, int(running_time % 60)) 670 else: 671 running_time = ' %ih %im ' % (running_time // 3600, (running_time//60 % 60)) 672 return running_time
673
674 675 #=============================================================================== 676 # TMP_directory (designed to work as with statement) 677 #=============================================================================== 678 -class TMP_directory(object):
679 """create a temporary directory and ensure this one to be cleaned. 680 """ 681
682 - def __init__(self, suffix='', prefix='tmp', dir=None):
683 self.nb_try_remove = 0 684 import tempfile 685 self.path = tempfile.mkdtemp(suffix, prefix, dir)
686 687
688 - def __exit__(self, ctype, value, traceback ):
689 try: 690 shutil.rmtree(self.path) 691 except OSError: 692 self.nb_try_remove += 1 693 if self.nb_try_remove < 3: 694 time.sleep(10) 695 self.__exit__(ctype, value, traceback) 696 else: 697 logger.warning("Directory %s not completely cleaned. This directory can be removed manually" % self.path)
698
699 - def __enter__(self):
700 return self.path
701 #
702 # GUNZIP/GZIP 703 # 704 -def gunzip(path, keep=False, stdout=None):
705 """ a standard replacement for os.system('gunzip -f %s.gz ' % event_path)""" 706 707 if not path.endswith(".gz"): 708 if os.path.exists("%s.gz" % path): 709 path = "%s.gz" % path 710 else: 711 raise Exception, "%(path)s does not finish by .gz and the file %(path)s.gz does not exists" %\ 712 {"path": path} 713 714 715 #for large file (>1G) it is faster and safer to use a separate thread 716 if os.path.getsize(path) > 1e8: 717 if stdout: 718 os.system('gunzip -c %s > %s' % (path, stdout)) 719 else: 720 os.system('gunzip %s' % path) 721 return 0 722 723 if not stdout: 724 stdout = path[:-3] 725 open(stdout,'w').write(ziplib.open(path, "r").read()) 726 if not keep: 727 os.remove(path) 728 return 0
729
730 -def gzip(path, stdout=None, error=True, forceexternal=False):
731 """ a standard replacement for os.system('gzip %s ' % path)""" 732 733 #for large file (>1G) it is faster and safer to use a separate thread 734 if os.path.getsize(path) > 1e9 or forceexternal: 735 call(['gzip', '-f', path]) 736 if stdout: 737 if not stdout.endswith(".gz"): 738 stdout = "%s.gz" % stdout 739 shutil.move('%s.gz' % path, stdout) 740 return 741 742 if not stdout: 743 stdout = "%s.gz" % path 744 elif not stdout.endswith(".gz"): 745 stdout = "%s.gz" % stdout 746 747 try: 748 ziplib.open(stdout,"w").write(open(path).read()) 749 except OverflowError: 750 gzip(path, stdout, error=error, forceexternal=True) 751 except Exception: 752 if error: 753 raise 754 else: 755 os.remove(path)
756
757 # 758 # Global function to open supported file types 759 # 760 -class open_file(object):
761 """ a convinient class to open a file """ 762 763 web_browser = None 764 eps_viewer = None 765 text_editor = None 766 configured = False 767
768 - def __init__(self, filename):
769 """open a file""" 770 771 # Check that the class is correctly configure 772 if not self.configured: 773 self.configure() 774 775 try: 776 extension = filename.rsplit('.',1)[1] 777 except IndexError: 778 extension = '' 779 780 781 # dispatch method 782 if extension in ['html','htm','php']: 783 self.open_program(self.web_browser, filename, background=True) 784 elif extension in ['ps','eps']: 785 self.open_program(self.eps_viewer, filename, background=True) 786 else: 787 self.open_program(self.text_editor,filename, mac_check=False)
788 # mac_check to False avoid to use open cmd in mac 789 790 @classmethod
791 - def configure(cls, configuration=None):
792 """ configure the way to open the file """ 793 794 cls.configured = True 795 796 # start like this is a configuration for mac 797 cls.configure_mac(configuration) 798 if sys.platform == 'darwin': 799 return # done for MAC 800 801 # on Mac some default (eps/web) might be kept on None. This is not 802 #suitable for LINUX which doesn't have open command. 803 804 # first for eps_viewer 805 if not cls.eps_viewer: 806 cls.eps_viewer = cls.find_valid(['evince','gv', 'ggv'], 'eps viewer') 807 808 # Second for web browser 809 if not cls.web_browser: 810 cls.web_browser = cls.find_valid( 811 ['firefox', 'chrome', 'safari','opera'], 812 'web browser')
813 814 @classmethod
815 - def configure_mac(cls, configuration=None):
816 """ configure the way to open a file for mac """ 817 818 if configuration is None: 819 configuration = {'text_editor': None, 820 'eps_viewer':None, 821 'web_browser':None} 822 823 for key in configuration: 824 if key == 'text_editor': 825 # Treat text editor ONLY text base editor !! 826 if configuration[key]: 827 program = configuration[key].split()[0] 828 if not which(program): 829 logger.warning('Specified text editor %s not valid.' % \ 830 configuration[key]) 831 else: 832 # All is good 833 cls.text_editor = configuration[key] 834 continue 835 #Need to find a valid default 836 if os.environ.has_key('EDITOR'): 837 cls.text_editor = os.environ['EDITOR'] 838 else: 839 cls.text_editor = cls.find_valid( 840 ['vi', 'emacs', 'vim', 'gedit', 'nano'], 841 'text editor') 842 843 elif key == 'eps_viewer': 844 if configuration[key]: 845 cls.eps_viewer = configuration[key] 846 continue 847 # else keep None. For Mac this will use the open command. 848 elif key == 'web_browser': 849 if configuration[key]: 850 cls.web_browser = configuration[key] 851 continue
852 # else keep None. For Mac this will use the open command. 853 854 @staticmethod
855 - def find_valid(possibility, program='program'):
856 """find a valid shell program in the list""" 857 858 for p in possibility: 859 if which(p): 860 logger.info('Using default %s \"%s\". ' % (program, p) + \ 861 'Set another one in ./input/mg5_configuration.txt') 862 return p 863 864 logger.info('No valid %s found. ' % program + \ 865 'Please set in ./input/mg5_configuration.txt') 866 return None
867 868
869 - def open_program(self, program, file_path, mac_check=True, background=False):
870 """ open a file with a given program """ 871 872 if mac_check==True and sys.platform == 'darwin': 873 return self.open_mac_program(program, file_path) 874 875 # Shell program only 876 if program: 877 arguments = program.split() # allow argument in program definition 878 arguments.append(file_path) 879 880 if not background: 881 subprocess.call(arguments) 882 else: 883 import thread 884 thread.start_new_thread(subprocess.call,(arguments,)) 885 else: 886 logger.warning('Not able to open file %s since no program configured.' % file_path + \ 887 'Please set one in ./input/mg5_configuration.txt')
888
889 - def open_mac_program(self, program, file_path):
890 """ open a text with the text editor """ 891 892 if not program: 893 # Ask to mac manager 894 os.system('open %s' % file_path) 895 elif which(program): 896 # shell program 897 arguments = program.split() # Allow argument in program definition 898 arguments.append(file_path) 899 subprocess.call(arguments) 900 else: 901 # not shell program 902 os.system('open -a %s %s' % (program, file_path))
903
904 -def is_executable(path):
905 """ check if a path is executable""" 906 try: 907 return os.access(path, os.X_OK) 908 except Exception: 909 return False
910
911 -class OptionParser(optparse.OptionParser):
912 """Option Peaser which raise an error instead as calling exit""" 913
914 - def exit(self, status=0, msg=None):
915 if msg: 916 raise InvalidCmd, msg 917 else: 918 raise InvalidCmd
919
920 -def sprint(*args, **opt):
921 """Returns the current line number in our program.""" 922 import inspect 923 if opt.has_key('log'): 924 log = opt['log'] 925 else: 926 log = logging.getLogger('madgraph') 927 if opt.has_key('level'): 928 level = opt['level'] 929 else: 930 level = logging.getLogger('madgraph').level 931 if level == 20: 932 level = 10 #avoid info level 933 lineno = inspect.currentframe().f_back.f_lineno 934 fargs = inspect.getframeinfo(inspect.currentframe().f_back) 935 filename, lineno = fargs[:2] 936 #file = inspect.currentframe().f_back.co_filename 937 #print type(file) 938 939 940 log.log(level, ' '.join([str(a) for a in args]) + \ 941 '\nraised at %s at line %s ' % (filename, lineno)) 942 943 return
944
945 ################################################################################ 946 # function to check if two float are approximatively equal 947 ################################################################################ 948 -def equal(a,b,sig_fig=6, zero_limit=True):
949 """function to check if two float are approximatively equal""" 950 import math 951 952 if not a or not b: 953 if zero_limit: 954 power = sig_fig + 1 955 else: 956 return a == b 957 else: 958 power = sig_fig - int(math.log10(abs(a))) + 1 959 960 return ( a==b or abs(int(a*10**power) - int(b*10**power)) < 10)
961
962 ################################################################################ 963 # class to change directory with the "with statement" 964 ################################################################################ 965 -class chdir:
966 - def __init__(self, newPath):
967 self.newPath = newPath
968
969 - def __enter__(self):
970 self.savedPath = os.getcwd() 971 os.chdir(self.newPath)
972
973 - def __exit__(self, etype, value, traceback):
974 os.chdir(self.savedPath)
975
976 977 978 ################################################################################ 979 # TAIL FUNCTION 980 ################################################################################ 981 -class digest:
982
983 - def test_all(self):
984 try: 985 return self.test_hashlib() 986 except Exception: 987 pass 988 try: 989 return self.test_md5() 990 except Exception: 991 pass 992 try: 993 return self.test_zlib() 994 except Exception: 995 pass
996
997 - def test_hashlib(self):
998 import hashlib 999 def digest(text): 1000 """using mg5 for the hash""" 1001 t = hashlib.md5() 1002 t.update(text) 1003 return t.hexdigest()
1004 return digest
1005
1006 - def test_md5(self):
1007 import md5 1008 def digest(text): 1009 """using mg5 for the hash""" 1010 t = md5.md5() 1011 t.update(text) 1012 return t.hexdigest()
1013 return digest 1014
1015 - def test_zlib(self):
1016 import zlib 1017 def digest(text): 1018 return zlib.adler32(text)
1019 1020 digest = digest().test_all() 1021