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') 721 return 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
729 -def gzip(path, stdout=None, error=True, forceexternal=False):
730 """ a standard replacement for os.system('gzip %s ' % path)""" 731 732 733 734 #for large file (>1G) it is faster and safer to use a separate thread 735 if os.path.getsize(path) > 1e9: 736 call(['gzip', '-f', path]) 737 if stdout: 738 shutil.move('%s.gz' % path, stdout) 739 return 740 741 if not stdout: 742 stdout = "%s.gz" % path 743 elif not stdout.endswith(".gz"): 744 stdout = "%s.gz" % stdout 745 746 try: 747 ziplib.open(stdout,"w").write(open(path).read()) 748 except OverflowError: 749 gzip(path, stdout, error=error, forceexternal=True) 750 except Exception: 751 if error: 752 raise 753 else: 754 os.remove(path)
755
756 # 757 # Global function to open supported file types 758 # 759 -class open_file(object):
760 """ a convinient class to open a file """ 761 762 web_browser = None 763 eps_viewer = None 764 text_editor = None 765 configured = False 766
767 - def __init__(self, filename):
768 """open a file""" 769 770 # Check that the class is correctly configure 771 if not self.configured: 772 self.configure() 773 774 try: 775 extension = filename.rsplit('.',1)[1] 776 except IndexError: 777 extension = '' 778 779 780 # dispatch method 781 if extension in ['html','htm','php']: 782 self.open_program(self.web_browser, filename, background=True) 783 elif extension in ['ps','eps']: 784 self.open_program(self.eps_viewer, filename, background=True) 785 else: 786 self.open_program(self.text_editor,filename, mac_check=False)
787 # mac_check to False avoid to use open cmd in mac 788 789 @classmethod
790 - def configure(cls, configuration=None):
791 """ configure the way to open the file """ 792 793 cls.configured = True 794 795 # start like this is a configuration for mac 796 cls.configure_mac(configuration) 797 if sys.platform == 'darwin': 798 return # done for MAC 799 800 # on Mac some default (eps/web) might be kept on None. This is not 801 #suitable for LINUX which doesn't have open command. 802 803 # first for eps_viewer 804 if not cls.eps_viewer: 805 cls.eps_viewer = cls.find_valid(['evince','gv', 'ggv'], 'eps viewer') 806 807 # Second for web browser 808 if not cls.web_browser: 809 cls.web_browser = cls.find_valid( 810 ['firefox', 'chrome', 'safari','opera'], 811 'web browser')
812 813 @classmethod
814 - def configure_mac(cls, configuration=None):
815 """ configure the way to open a file for mac """ 816 817 if configuration is None: 818 configuration = {'text_editor': None, 819 'eps_viewer':None, 820 'web_browser':None} 821 822 for key in configuration: 823 if key == 'text_editor': 824 # Treat text editor ONLY text base editor !! 825 if configuration[key]: 826 program = configuration[key].split()[0] 827 if not which(program): 828 logger.warning('Specified text editor %s not valid.' % \ 829 configuration[key]) 830 else: 831 # All is good 832 cls.text_editor = configuration[key] 833 continue 834 #Need to find a valid default 835 if os.environ.has_key('EDITOR'): 836 cls.text_editor = os.environ['EDITOR'] 837 else: 838 cls.text_editor = cls.find_valid( 839 ['vi', 'emacs', 'vim', 'gedit', 'nano'], 840 'text editor') 841 842 elif key == 'eps_viewer': 843 if configuration[key]: 844 cls.eps_viewer = configuration[key] 845 continue 846 # else keep None. For Mac this will use the open command. 847 elif key == 'web_browser': 848 if configuration[key]: 849 cls.web_browser = configuration[key] 850 continue
851 # else keep None. For Mac this will use the open command. 852 853 @staticmethod
854 - def find_valid(possibility, program='program'):
855 """find a valid shell program in the list""" 856 857 for p in possibility: 858 if which(p): 859 logger.info('Using default %s \"%s\". ' % (program, p) + \ 860 'Set another one in ./input/mg5_configuration.txt') 861 return p 862 863 logger.info('No valid %s found. ' % program + \ 864 'Please set in ./input/mg5_configuration.txt') 865 return None
866 867
868 - def open_program(self, program, file_path, mac_check=True, background=False):
869 """ open a file with a given program """ 870 871 if mac_check==True and sys.platform == 'darwin': 872 return self.open_mac_program(program, file_path) 873 874 # Shell program only 875 if program: 876 arguments = program.split() # allow argument in program definition 877 arguments.append(file_path) 878 879 if not background: 880 subprocess.call(arguments) 881 else: 882 import thread 883 thread.start_new_thread(subprocess.call,(arguments,)) 884 else: 885 logger.warning('Not able to open file %s since no program configured.' % file_path + \ 886 'Please set one in ./input/mg5_configuration.txt')
887
888 - def open_mac_program(self, program, file_path):
889 """ open a text with the text editor """ 890 891 if not program: 892 # Ask to mac manager 893 os.system('open %s' % file_path) 894 elif which(program): 895 # shell program 896 arguments = program.split() # Allow argument in program definition 897 arguments.append(file_path) 898 subprocess.call(arguments) 899 else: 900 # not shell program 901 os.system('open -a %s %s' % (program, file_path))
902
903 -def is_executable(path):
904 """ check if a path is executable""" 905 try: 906 return os.access(path, os.X_OK) 907 except Exception: 908 return False
909
910 -class OptionParser(optparse.OptionParser):
911 """Option Peaser which raise an error instead as calling exit""" 912
913 - def exit(self, status=0, msg=None):
914 if msg: 915 raise InvalidCmd, msg 916 else: 917 raise InvalidCmd
918
919 -def sprint(*args, **opt):
920 """Returns the current line number in our program.""" 921 import inspect 922 if opt.has_key('log'): 923 log = opt['log'] 924 else: 925 log = logging.getLogger('madgraph') 926 if opt.has_key('level'): 927 level = opt['level'] 928 else: 929 level = logging.getLogger('madgraph').level 930 if level == 20: 931 level = 10 #avoid info level 932 lineno = inspect.currentframe().f_back.f_lineno 933 fargs = inspect.getframeinfo(inspect.currentframe().f_back) 934 filename, lineno = fargs[:2] 935 #file = inspect.currentframe().f_back.co_filename 936 #print type(file) 937 938 939 log.log(level, ' '.join([str(a) for a in args]) + \ 940 '\nraised at %s at line %s ' % (filename, lineno)) 941 942 return
943
944 ################################################################################ 945 # function to check if two float are approximatively equal 946 ################################################################################ 947 -def equal(a,b,sig_fig=6, zero_limit=True):
948 """function to check if two float are approximatively equal""" 949 import math 950 951 if not a or not b: 952 if zero_limit: 953 power = sig_fig + 1 954 else: 955 return a == b 956 else: 957 power = sig_fig - int(math.log10(abs(a))) + 1 958 959 return ( a==b or abs(int(a*10**power) - int(b*10**power)) < 10)
960
961 ################################################################################ 962 # class to change directory with the "with statement" 963 ################################################################################ 964 -class chdir:
965 - def __init__(self, newPath):
966 self.newPath = newPath
967
968 - def __enter__(self):
969 self.savedPath = os.getcwd() 970 os.chdir(self.newPath)
971
972 - def __exit__(self, etype, value, traceback):
973 os.chdir(self.savedPath)
974
975 976 977 ################################################################################ 978 # TAIL FUNCTION 979 ################################################################################ 980 -class digest:
981
982 - def test_all(self):
983 try: 984 return self.test_hashlib() 985 except Exception: 986 pass 987 try: 988 return self.test_md5() 989 except Exception: 990 pass 991 try: 992 return self.test_zlib() 993 except Exception: 994 pass
995
996 - def test_hashlib(self):
997 import hashlib 998 def digest(text): 999 """using mg5 for the hash""" 1000 t = hashlib.md5() 1001 t.update(text) 1002 return t.hexdigest()
1003 return digest
1004
1005 - def test_md5(self):
1006 import md5 1007 def digest(text): 1008 """using mg5 for the hash""" 1009 t = md5.md5() 1010 t.update(text) 1011 return t.hexdigest()
1012 return digest 1013
1014 - def test_zlib(self):
1015 import zlib 1016 def digest(text): 1017 return zlib.adler32(text)
1018 1019 digest = digest().test_all() 1020