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 MadGraph Development team and Contributors 
  4  # 
  5  # This file is a part of the MadGraph 5 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 MadGraph license which should accompany this  
 10  # distribution. 
 11  # 
 12  # For more information, please visit: http://madgraph.phys.ucl.ac.be 
 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 time 
 27   
 28  try: 
 29      # Use in MadGraph 
 30      import madgraph 
 31      from madgraph import MadGraph5Error 
 32      import madgraph.iolibs.files as files 
 33  except: 
 34      # Use in MadEvent 
 35      import internal as madgraph 
 36      from internal import MadGraph5Error 
 37      import internal.files as files 
 38       
 39  logger = logging.getLogger('cmdprint.ext_program') 
 40  pjoin = os.path.join 
41 42 #=============================================================================== 43 # parse_info_str 44 #=============================================================================== 45 -def parse_info_str(fsock):
46 """Parse a newline separated list of "param=value" as a dictionnary 47 """ 48 49 info_dict = {} 50 pattern = re.compile("(?P<name>\w*)\s*=\s*(?P<value>.*)", 51 re.IGNORECASE | re.VERBOSE) 52 for entry in fsock: 53 entry = entry.strip() 54 if len(entry) == 0: continue 55 m = pattern.match(entry) 56 if m is not None: 57 info_dict[m.group('name')] = m.group('value') 58 else: 59 raise IOError, "String %s is not a valid info string" % entry 60 61 return info_dict
62
63 64 #=============================================================================== 65 # get_pkg_info 66 #=============================================================================== 67 -def get_pkg_info(info_str=None):
68 """Returns the current version information of the MadGraph package, 69 as written in the VERSION text file. If the file cannot be found, 70 a dictionary with empty values is returned. As an option, an info 71 string can be passed to be read instead of the file content. 72 """ 73 74 if info_str is None: 75 info_dict = files.read_from_file(os.path.join(madgraph.__path__[0], 76 "VERSION"), 77 parse_info_str, 78 print_error=False) 79 else: 80 info_dict = parse_info_str(StringIO.StringIO(info_str)) 81 82 return info_dict
83
84 #=============================================================================== 85 # get_time_info 86 #=============================================================================== 87 -def get_time_info():
88 """Returns the present time info for use in MG5 command history header. 89 """ 90 91 creation_time = time.asctime() 92 time_info = {'time': creation_time, 93 'fill': ' ' * (26 - len(creation_time))} 94 95 return time_info
96
97 #=============================================================================== 98 # find a executable 99 #=============================================================================== 100 -def which(program):
101 def is_exe(fpath): 102 return os.path.exists(fpath) and os.access(fpath, os.X_OK)
103 104 if not program: 105 return None 106 107 fpath, fname = os.path.split(program) 108 if fpath: 109 if is_exe(program): 110 return program 111 else: 112 for path in os.environ["PATH"].split(os.pathsep): 113 exe_file = os.path.join(path, program) 114 if is_exe(exe_file): 115 return exe_file 116 117 return None 118
119 #=============================================================================== 120 # Return Nice display for a random variable 121 #=============================================================================== 122 -def nice_representation(var, nb_space=0):
123 """ Return nice information on the current variable """ 124 125 #check which data to put: 126 info = [('type',type(var)),('str', var)] 127 if hasattr(var, 'func_doc'): 128 info.append( ('DOC', var.func_doc) ) 129 if hasattr(var, '__doc__'): 130 info.append( ('DOC', var.__doc__) ) 131 if hasattr(var, '__dict__'): 132 info.append( ('ATTRIBUTE', var.__dict__.keys() )) 133 134 spaces = ' ' * nb_space 135 136 outstr='' 137 for name, value in info: 138 outstr += '%s%3s : %s\n' % (spaces,name, value) 139 140 return outstr
141
142 143 #=============================================================================== 144 # Compiler which returns smart output error in case of trouble 145 #=============================================================================== 146 -def compile(arg=[], cwd=None, mode='fortran', **opt):
147 """compile a given directory""" 148 149 try: 150 p = subprocess.Popen(['make'] + arg, stdout=subprocess.PIPE, 151 stderr=subprocess.STDOUT, cwd=cwd, **opt) 152 (out, err) = p.communicate() 153 except OSError, error: 154 if cwd and not os.path.exists(cwd): 155 raise OSError, 'Directory %s doesn\'t exists. Impossible to run make' % cwd 156 else: 157 error_text = "Impossible to compile %s directory\n" % cwd 158 error_text += "Trying to launch make command returns:\n" 159 error_text += " " + str(error) + "\n" 160 error_text += "In general this means that your computer is not able to compile." 161 if sys.platform == "darwin": 162 error_text += "Note that MacOSX doesn\'t have gmake/gfortan install by default.\n" 163 error_text += "Xcode3 contains those require program" 164 raise MadGraph5Error, error_text 165 166 if p.returncode: 167 # Check that makefile exists 168 if not cwd: 169 cwd = os.getcwd() 170 all_file = [f.lower() for f in os.listdir(cwd)] 171 if 'makefile' not in all_file: 172 raise OSError, 'no makefile present in %s' % os.path.realpath(cwd) 173 174 if mode == 'fortran' and not (which('g77') or which('gfortran')): 175 error_msg = 'A fortran compilator (g77 or gfortran) is required to create this output.\n' 176 error_msg += 'Please install g77 or gfortran on your computer and retry.' 177 raise MadGraph5Error, error_msg 178 elif mode == 'cpp' and not which('g++'): 179 error_msg ='A C++ compilator (g++) is required to create this output.\n' 180 error_msg += 'Please install g++ (which is part of the gcc package) on your computer and retry.' 181 raise MadGraph5Error, error_msg 182 183 # Other reason 184 185 error_text = 'A compilation Error occurs ' 186 if cwd: 187 error_text += 'when trying to compile %s.\n' % cwd 188 error_text += 'The compilation fails with the following output message:\n' 189 error_text += ' '+out.replace('\n','\n ')+'\n' 190 error_text += 'Please try to fix this compilations issue and retry.\n' 191 error_text += 'Help might be found at https://answers.launchpad.net/madgraph5.\n' 192 error_text += 'If you think that this is a bug, you can report this at https://bugs.launchpad.net/madgraph5' 193 194 raise MadGraph5Error, error_text 195 return p.returncode
196
197 # Control 198 -def check_system_error(value=1):
199 def deco_check(f): 200 def deco_f(arg, *args, **opt): 201 try: 202 return f(arg, *args, **opt) 203 except OSError, error: 204 if isinstance(arg, list): 205 prog = arg[0] 206 else: 207 prog = arg[0] 208 209 # Permission denied 210 if error.errno == 13: 211 if os.path.exists(prog): 212 os.system('chmod +x %s' % prog) 213 elif 'cwd' in opt and opt['cwd'] and \ 214 os.path.isfile(pjoin(opt['cwd'],arg[0])): 215 os.system('chmod +x %s' % pjoin(opt['cwd'],arg[0])) 216 return f(arg, *args, **opt) 217 # NO such file or directory 218 elif error.errno == 2: 219 # raise a more meaningfull error message 220 raise Exception, '%s fails with no such file or directory' \ 221 % arg 222 else: 223 raise
224 return deco_f 225 return deco_check 226
227 228 @check_system_error() 229 -def call(arg, *args, **opt):
230 """nice way to call an external program with nice error treatment""" 231 return subprocess.call(arg, *args, **opt)
232
233 @check_system_error() 234 -def Popen(arg, *args, **opt):
235 """nice way to call an external program with nice error treatment""" 236 return subprocess.Popen(arg, *args, **opt)
237
238 239 240 241 242 ################################################################################ 243 # TAIL FUNCTION 244 ################################################################################ 245 -def tail(f, n, offset=None):
246 """Reads a n lines from f with an offset of offset lines. The return 247 value is a tuple in the form ``lines``. 248 """ 249 avg_line_length = 74 250 to_read = n + (offset or 0) 251 252 while 1: 253 try: 254 f.seek(-(avg_line_length * to_read), 2) 255 except IOError: 256 # woops. apparently file is smaller than what we want 257 # to step back, go to the beginning instead 258 f.seek(0) 259 pos = f.tell() 260 lines = f.read().splitlines() 261 if len(lines) >= to_read or pos == 0: 262 return lines[-to_read:offset and -offset or None] 263 avg_line_length *= 1.3 264 avg_line_length = int(avg_line_length)
265
266 ################################################################################ 267 # LAST LINE FUNCTION 268 ################################################################################ 269 -def get_last_line(fsock):
270 """return the last line of a file""" 271 272 return tail(fsock, 1)[0]
273
274 -class BackRead(file):
275 """read a file returning the lines in reverse order for each call of readline() 276 This actually just reads blocks (4096 bytes by default) of data from the end of 277 the file and returns last line in an internal buffer.""" 278 279
280 - def readline(self):
281 """ readline in a backward way """ 282 283 while len(self.data) == 1 and ((self.blkcount * self.blksize) < self.size): 284 self.blkcount = self.blkcount + 1 285 line = self.data[0] 286 try: 287 self.seek(-self.blksize * self.blkcount, 2) # read from end of file 288 self.data = (self.read(self.blksize) + line).split('\n') 289 except IOError: # can't seek before the beginning of the file 290 self.seek(0) 291 data = self.read(self.size - (self.blksize * (self.blkcount-1))) + line 292 self.data = data.split('\n') 293 294 if len(self.data) == 0: 295 return "" 296 297 line = self.data.pop() 298 return line + '\n'
299
300 - def __init__(self, filepos, blksize=4096):
301 """initialize the internal structures""" 302 303 # get the file size 304 self.size = os.stat(filepos)[6] 305 # how big of a block to read from the file... 306 self.blksize = blksize 307 # how many blocks we've read 308 self.blkcount = 1 309 file.__init__(self, filepos, 'rb') 310 # if the file is smaller than the blocksize, read a block, 311 # otherwise, read the whole thing... 312 if self.size > self.blksize: 313 self.seek(-self.blksize * self.blkcount, 2) # read from end of file 314 self.data = self.read(self.blksize).split('\n') 315 # strip the last item if it's empty... a byproduct of the last line having 316 # a newline at the end of it 317 if not self.data[-1]: 318 self.data.pop()
319
320 - def next(self):
321 line = self.readline() 322 if line: 323 return line 324 else: 325 raise StopIteration
326
327 328 329 330 # 331 # Global function to open supported file types 332 # 333 -class open_file(object):
334 """ a convinient class to open a file """ 335 336 web_browser = None 337 eps_viewer = None 338 text_editor = None 339 configured = False 340
341 - def __init__(self, filename):
342 """open a file""" 343 344 # Check that the class is correctly configure 345 if not self.configured: 346 self.configure() 347 348 try: 349 extension = filename.rsplit('.',1)[1] 350 except IndexError: 351 extension = '' 352 353 354 # dispatch method 355 if extension in ['html','htm','php']: 356 self.open_program(self.web_browser, filename, background=True) 357 elif extension in ['ps','eps']: 358 self.open_program(self.eps_viewer, filename, background=True) 359 else: 360 self.open_program(self.text_editor,filename, mac_check=False)
361 # mac_check to False avoid to use open cmd in mac 362 363 @classmethod
364 - def configure(cls, configuration=None):
365 """ configure the way to open the file """ 366 367 cls.configured = True 368 369 # start like this is a configuration for mac 370 cls.configure_mac(configuration) 371 if sys.platform == 'darwin': 372 return # done for MAC 373 374 # on Mac some default (eps/web) might be kept on None. This is not 375 #suitable for LINUX which doesn't have open command. 376 377 # first for eps_viewer 378 if not cls.eps_viewer: 379 cls.eps_viewer = cls.find_valid(['gv', 'ggv', 'evince'], 'eps viewer') 380 381 # Second for web browser 382 if not cls.web_browser: 383 cls.web_browser = cls.find_valid( 384 ['firefox', 'chrome', 'safari','opera'], 385 'web browser')
386 387 @classmethod
388 - def configure_mac(cls, configuration=None):
389 """ configure the way to open a file for mac """ 390 391 if configuration is None: 392 configuration = {'text_editor': None, 393 'eps_viewer':None, 394 'web_browser':None} 395 396 for key in configuration: 397 if key == 'text_editor': 398 # Treat text editor ONLY text base editor !! 399 if configuration[key]: 400 program = configuration[key].split()[0] 401 if not which(program): 402 logger.warning('Specified text editor %s not valid.' % \ 403 configuration[key]) 404 else: 405 # All is good 406 cls.text_editor = configuration[key] 407 continue 408 #Need to find a valid default 409 if os.environ.has_key('EDITOR'): 410 cls.text_editor = os.environ['EDITOR'] 411 else: 412 cls.text_editor = cls.find_valid( 413 ['vi', 'emacs', 'vim', 'gedit', 'nano'], 414 'text editor') 415 416 elif key == 'eps_viewer': 417 if configuration[key]: 418 cls.eps_viewer = configuration[key] 419 continue 420 # else keep None. For Mac this will use the open command. 421 elif key == 'web_browser': 422 if configuration[key]: 423 cls.web_browser = configuration[key] 424 continue
425 # else keep None. For Mac this will use the open command. 426 427 @staticmethod
428 - def find_valid(possibility, program='program'):
429 """find a valid shell program in the list""" 430 431 for p in possibility: 432 if which(p): 433 logger.info('Using default %s \"%s\". ' % (program, p) + \ 434 'Set another one in ./input/mg5_configuration.txt') 435 return p 436 437 logger.info('No valid %s found. ' % program + \ 438 'Please set in ./input/mg5_configuration.txt') 439 return None
440 441
442 - def open_program(self, program, file_path, mac_check=True, background=False):
443 """ open a file with a given program """ 444 445 if mac_check==True and sys.platform == 'darwin': 446 return self.open_mac_program(program, file_path) 447 448 # Shell program only 449 if program: 450 arguments = program.split() # allow argument in program definition 451 arguments.append(file_path) 452 453 if not background: 454 subprocess.call(arguments) 455 else: 456 import thread 457 thread.start_new_thread(subprocess.call,(arguments,)) 458 else: 459 logger.warning('Not able to open file %s since no program configured.' % file_path + \ 460 'Please set one in ./input/mg5_configuration.txt')
461
462 - def open_mac_program(self, program, file_path):
463 """ open a text with the text editor """ 464 465 if not program: 466 # Ask to mac manager 467 os.system('open %s' % file_path) 468 elif which(program): 469 # shell program 470 arguments = program.split() # Allow argument in program definition 471 arguments.append(file_path) 472 subprocess.call(arguments) 473 else: 474 # not shell program 475 os.system('open -a %s %s' % (program, file_path))
476
477 -def is_executable(path):
478 """ check if a path is executable""" 479 try: 480 return os.access(path, os.X_OK) 481 except: 482 return False
483