1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """A set of functions performing routine administrative I/O tasks."""
17
18 import contextlib
19 import logging
20 import os
21 import re
22 import signal
23 import subprocess
24 import sys
25 import StringIO
26 import sys
27 import optparse
28 import time
29 import shutil
30 import traceback
31 import gzip as ziplib
32
33 try:
34
35 import madgraph
36 except Exception, error:
37
38 import internal
39 from internal import MadGraph5Error, InvalidCmd
40 import internal.files as files
41 MADEVENT = True
42 else:
43 from madgraph import MadGraph5Error, InvalidCmd
44 import madgraph.iolibs.files as files
45 MADEVENT = False
46
47
48
49 logger = logging.getLogger('cmdprint.ext_program')
50 logger_stderr = logging.getLogger('madevent.misc')
51 pjoin = os.path.join
59 """ Check the consistency of the mg5amc_py8_interface installed with
60 the current MG5 and Pythia8 versions. """
61
62 return None
63
64 if not options['pythia8_path']:
65 return None
66
67 if not options['mg5amc_py8_interface_path']:
68 return \
69 """
70 A Pythia8 path is specified via the option 'pythia8_path' but no path for option
71 'mg5amc_py8_interface_path' is specified. This means that Pythia8 cannot be used
72 leading order simulations with MadEvent.
73 Consider installing the MG5_aMC-PY8 interface with the following command:
74 MG5_aMC>install mg5amc_py8_interface
75 """
76
77
78 MG5_version_on_install = open(pjoin(options['mg5amc_py8_interface_path'],
79 'MG5AMC_VERSION_ON_INSTALL')).read().replace('\n','')
80 if MG5_version_on_install == 'UNSPECIFIED':
81 MG5_version_on_install = None
82 PY8_version_on_install = open(pjoin(options['mg5amc_py8_interface_path'],
83 'PYTHIA8_VERSION_ON_INSTALL')).read().replace('\n','')
84 MG5_curr_version = get_pkg_info()['version']
85 try:
86 p = subprocess.Popen(['./get_pythia8_version.py',options['pythia8_path']],
87 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
88 cwd=options['mg5amc_py8_interface_path'])
89 (out, err) = p.communicate()
90 out = out.replace('\n','')
91 PY8_curr_version = out
92
93
94 float(out)
95 except:
96 PY8_curr_version = None
97
98 if not MG5_version_on_install is None and not MG5_curr_version is None:
99 if MG5_version_on_install != MG5_curr_version:
100 return \
101 """
102 The current version of MG5_aMC (v%s) is different than the one active when
103 installing the 'mg5amc_py8_interface_path' (which was MG5aMC v%s).
104 Please consider refreshing the installation of this interface with the command:
105 MG5_aMC>install mg5amc_py8_interface
106 """%(MG5_curr_version, MG5_version_on_install)
107
108 if not PY8_version_on_install is None and not PY8_curr_version is None:
109 if PY8_version_on_install != PY8_curr_version:
110 return \
111 """
112 The current version of Pythia8 (v%s) is different than the one active when
113 installing the 'mg5amc_py8_interface' tool (which was Pythia8 v%s).
114 Please consider refreshing the installation of this interface with the command:
115 MG5_aMC>install mg5amc_py8_interface
116 """%(PY8_curr_version,PY8_version_on_install)
117
118 return None
119
126 """Parse a newline separated list of "param=value" as a dictionnary
127 """
128
129 info_dict = {}
130 pattern = re.compile("(?P<name>\w*)\s*=\s*(?P<value>.*)",
131 re.IGNORECASE | re.VERBOSE)
132 for entry in fsock:
133 entry = entry.strip()
134 if len(entry) == 0: continue
135 m = pattern.match(entry)
136 if m is not None:
137 info_dict[m.group('name')] = m.group('value')
138 else:
139 raise IOError, "String %s is not a valid info string" % entry
140
141 return info_dict
142
143
144
145
146
147 -def mute_logger(names=['madgraph','ALOHA','cmdprint','madevent'], levels=[50,50,50,50]):
148 """change the logger level and restore those at their initial value at the
149 end of the function decorated."""
150 def control_logger(f):
151 def restore_old_levels(names, levels):
152 for name, level in zip(names, levels):
153 log_module = logging.getLogger(name)
154 log_module.setLevel(level)
155
156 def f_with_no_logger(self, *args, **opt):
157 old_levels = []
158 for name, level in zip(names, levels):
159 log_module = logging.getLogger(name)
160 old_levels.append(log_module.level)
161 log_module.setLevel(level)
162 try:
163 out = f(self, *args, **opt)
164 restore_old_levels(names, old_levels)
165 return out
166 except:
167 restore_old_levels(names, old_levels)
168 raise
169
170 return f_with_no_logger
171 return control_logger
172
177 """Returns the current version information of the MadGraph5_aMC@NLO package,
178 as written in the VERSION text file. If the file cannot be found,
179 a dictionary with empty values is returned. As an option, an info
180 string can be passed to be read instead of the file content.
181 """
182
183 if info_str:
184 info_dict = parse_info_str(StringIO.StringIO(info_str))
185
186 elif MADEVENT:
187 info_dict ={}
188 info_dict['version'] = open(pjoin(internal.__path__[0],'..','..','MGMEVersion.txt')).read().strip()
189 info_dict['date'] = '20xx-xx-xx'
190 else:
191 info_dict = files.read_from_file(os.path.join(madgraph.__path__[0],
192 "VERSION"),
193 parse_info_str,
194 print_error=False)
195
196 return info_dict
197
202 """Returns the present time info for use in MG5 command history header.
203 """
204
205 creation_time = time.asctime()
206 time_info = {'time': creation_time,
207 'fill': ' ' * (26 - len(creation_time))}
208
209 return time_info
210
215 """Browse the subdirectories of the path 'start_path' and returns the first
216 one found which contains at least one file ending with the string extension
217 given in argument."""
218
219 subdirs=[pjoin(start_path,dir) for dir in os.listdir(start_path)]
220 for subdir in subdirs:
221 if os.path.isfile(subdir):
222 if os.path.basename(subdir).endswith(extension):
223 return start_path
224 elif os.path.isdir(subdir):
225 path = find_includes_path(subdir, extension)
226 if path:
227 return path
228 return None
229
235 """ Get whether ninja supports quad prec in different ways"""
236
237
238 ninja_config = os.path.abspath(pjoin(
239 ninja_lib_path,os.pardir,'bin','ninja-config'))
240 if os.path.exists(ninja_config):
241 try:
242 p = Popen([ninja_config, '-quadsupport'], stdout=subprocess.PIPE,
243 stderr=subprocess.PIPE)
244 output, error = p.communicate()
245 return 'TRUE' in output.upper()
246 except Exception:
247 pass
248
249
250
251 return False
252
253
254
255
256 -def which(program):
257 def is_exe(fpath):
258 return os.path.exists(fpath) and os.access(\
259 os.path.realpath(fpath), os.X_OK)
260
261 if not program:
262 return None
263
264 fpath, fname = os.path.split(program)
265 if fpath:
266 if is_exe(program):
267 return program
268 else:
269 for path in os.environ["PATH"].split(os.pathsep):
270 exe_file = os.path.join(path, program)
271 if is_exe(exe_file):
272 return exe_file
273 return None
274
290
296 """ Make sure to turn off some dependency of MG5aMC. """
297
298 def tell(msg):
299 if log == 'stdout':
300 print msg
301 elif callable(log):
302 log(msg)
303
304
305 if dependency in ['pjfry','golem','samurai','ninja']:
306 if cmd.options[dependency] not in ['None',None,'']:
307 tell("Deactivating MG5_aMC dependency '%s'"%dependency)
308 cmd.options[dependency] = None
309
311 """ Checks whether the specfieid MG dependency can be activated if it was
312 not turned off in MG5 options."""
313
314 def tell(msg):
315 if log == 'stdout':
316 print msg
317 elif callable(log):
318 log(msg)
319
320 if cmd is None:
321 cmd = MGCmd.MasterCmd()
322
323 if dependency=='pjfry':
324 if cmd.options['pjfry'] in ['None',None,''] or \
325 (cmd.options['pjfry'] == 'auto' and which_lib('libpjfry.a') is None) or\
326 which_lib(pjoin(cmd.options['pjfry'],'libpjfry.a')) is None:
327 tell("Installing PJFry...")
328 cmd.do_install('PJFry')
329
330 if dependency=='golem':
331 if cmd.options['golem'] in ['None',None,''] or\
332 (cmd.options['golem'] == 'auto' and which_lib('libgolem.a') is None) or\
333 which_lib(pjoin(cmd.options['golem'],'libgolem.a')) is None:
334 tell("Installing Golem95...")
335 cmd.do_install('Golem95')
336
337 if dependency=='samurai':
338 raise MadGraph5Error, 'Samurai cannot yet be automatically installed.'
339
340 if dependency=='ninja':
341 if cmd.options['ninja'] in ['None',None,''] or\
342 (cmd.options['ninja'] == './HEPTools/lib' and not MG5dir is None and\
343 which_lib(pjoin(MG5dir,cmd.options['ninja'],'libninja.a')) is None):
344 tell("Installing ninja...")
345 cmd.do_install('ninja')
346
351 def is_lib(fpath):
352 return os.path.exists(fpath) and os.access(fpath, os.R_OK)
353
354 if not lib:
355 return None
356
357 fpath, fname = os.path.split(lib)
358 if fpath:
359 if is_lib(lib):
360 return lib
361 else:
362 locations = sum([os.environ[env_path].split(os.pathsep) for env_path in
363 ["DYLD_LIBRARY_PATH","LD_LIBRARY_PATH","LIBRARY_PATH","PATH"]
364 if env_path in os.environ],[])
365 for path in locations:
366 lib_file = os.path.join(path, lib)
367 if is_lib(lib_file):
368 return lib_file
369 return None
370
375 """ Return nice information on the current variable """
376
377
378 info = [('type',type(var)),('str', var)]
379 if hasattr(var, 'func_doc'):
380 info.append( ('DOC', var.func_doc) )
381 if hasattr(var, '__doc__'):
382 info.append( ('DOC', var.__doc__) )
383 if hasattr(var, '__dict__'):
384 info.append( ('ATTRIBUTE', var.__dict__.keys() ))
385
386 spaces = ' ' * nb_space
387
388 outstr=''
389 for name, value in info:
390 outstr += '%s%3s : %s\n' % (spaces,name, value)
391
392 return outstr
393
394
395
396
397 wait_once = False
399
400 def deco_retry(f):
401 def deco_f_retry(*args, **opt):
402 for i in range(nb_try):
403 try:
404 return f(*args, **opt)
405 except KeyboardInterrupt:
406 raise
407 except Exception, error:
408 global wait_once
409 if not wait_once:
410 text = """Start waiting for update. (more info in debug mode)"""
411 logger.info(text)
412 logger_stderr.debug('fail to do %s function with %s args. %s try on a max of %s (%s waiting time)' %
413 (str(f), ', '.join([str(a) for a in args]), i+1, nb_try, sleep * (i+1)))
414 logger_stderr.debug('error is %s' % str(error))
415 if __debug__: logger_stderr.debug('and occurred at :'+traceback.format_exc())
416 wait_once = True
417 time.sleep(sleep * (i+1))
418
419 if __debug__:
420 raise
421 raise error.__class__, '[Fail %i times] \n %s ' % (i+1, error)
422 return deco_f_retry
423 return deco_retry
424
429 """return a name of the type xxxx[A-B]yyy
430 where xxx and yyy are the common part between the two names.
431 """
432
433
434 base = [first[i] for i in range(len(first)) if first[:i+1] == last[:i+1]]
435
436 while base and base[0].isdigit():
437 base = base[1:]
438
439 end = [first[-(i+1)] for i in range(len(first)) if first[-(i+1):] == last[-(i+1):]]
440
441 while end and end[-1].isdigit():
442 end = end[:-1]
443 end.reverse()
444
445 base, end = ''.join(base), ''.join(end)
446 if end:
447 name = "%s[%s-%s]%s" % (base, first[len(base):-len(end)], last[len(base):-len(end)],end)
448 else:
449 name = "%s[%s-%s]%s" % (base, first[len(base):], last[len(base):],end)
450 return name
451
452
453
454
455 -def compile(arg=[], cwd=None, mode='fortran', job_specs = True, nb_core=1 ,**opt):
456 """compile a given directory"""
457
458 cmd = ['make']
459 try:
460 if nb_core > 1:
461 cmd.append('-j%s' % nb_core)
462 cmd += arg
463 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
464 stderr=subprocess.STDOUT, cwd=cwd, **opt)
465 (out, err) = p.communicate()
466 except OSError, error:
467 if cwd and not os.path.exists(cwd):
468 raise OSError, 'Directory %s doesn\'t exists. Impossible to run make' % cwd
469 else:
470 error_text = "Impossible to compile %s directory\n" % cwd
471 error_text += "Trying to launch make command returns:\n"
472 error_text += " " + str(error) + "\n"
473 error_text += "In general this means that your computer is not able to compile."
474 if sys.platform == "darwin":
475 error_text += "Note that MacOSX doesn\'t have gmake/gfortan install by default.\n"
476 error_text += "Xcode3 contains those required programs"
477 raise MadGraph5Error, error_text
478
479 if p.returncode:
480
481 if not cwd:
482 cwd = os.getcwd()
483 all_file = [f.lower() for f in os.listdir(cwd)]
484 if 'makefile' not in all_file:
485 raise OSError, 'no makefile present in %s' % os.path.realpath(cwd)
486
487 if mode == 'fortran' and not (which('g77') or which('gfortran')):
488 error_msg = 'A fortran compiler (g77 or gfortran) is required to create this output.\n'
489 error_msg += 'Please install g77 or gfortran on your computer and retry.'
490 raise MadGraph5Error, error_msg
491 elif mode == 'cpp' and not which('g++'):
492 error_msg ='A C++ compiler (g++) is required to create this output.\n'
493 error_msg += 'Please install g++ (which is part of the gcc package) on your computer and retry.'
494 raise MadGraph5Error, error_msg
495
496
497 if any(tag.upper() in out.upper() for tag in ['real(kind=16)','real*16',
498 'complex*32']) and mode == 'fortran' and not \
499 ''.join(get_gfortran_version().split('.')) >= '46':
500 if not which('gfortran'):
501 raise MadGraph5Error, 'The fortran compiler gfortran v4.6 or later '+\
502 'is required to compile %s.\nPlease install it and retry.'%cwd
503 else:
504 logger_stderr.error('ERROR, you could not compile %s because'%cwd+\
505 ' your version of gfortran is older than 4.6. MadGraph5_aMC@NLO will carry on,'+\
506 ' but will not be able to compile an executable.')
507 return p.returncode
508
509 error_text = 'A compilation Error occurs '
510 if cwd:
511 error_text += 'when trying to compile %s.\n' % cwd
512 error_text += 'The compilation fails with the following output message:\n'
513 error_text += ' '+out.replace('\n','\n ')+'\n'
514 error_text += 'Please try to fix this compilations issue and retry.\n'
515 error_text += 'Help might be found at https://answers.launchpad.net/mg5amcnlo.\n'
516 error_text += 'If you think that this is a bug, you can report this at https://bugs.launchpad.net/mg5amcnlo'
517 raise MadGraph5Error, error_text
518 return p.returncode
519
521 """ Returns the gfortran version as a string.
522 Returns '0' if it failed."""
523 try:
524 p = Popen([compiler, '-dumpversion'], stdout=subprocess.PIPE,
525 stderr=subprocess.PIPE)
526 output, error = p.communicate()
527 version_finder=re.compile(r"(?P<version>(\d.)*\d)")
528 version = version_finder.search(output).group('version')
529 return version
530 except Exception:
531 return '0'
532
533 -def mod_compilator(directory, new='gfortran', current=None, compiler_type='gfortran'):
534
535 if type(directory)!=list:
536 directory=[directory]
537
538
539 file_to_change=find_makefile_in_dir(directory)
540 if compiler_type == 'gfortran':
541 comp_re = re.compile('^(\s*)FC\s*=\s*(.+)\s*$')
542 var = 'FC'
543 elif compiler_type == 'cpp':
544 comp_re = re.compile('^(\s*)CXX\s*=\s*(.+)\s*$')
545 var = 'CXX'
546 else:
547 MadGraph5Error, 'Unknown compiler type: %s' % compiler_type
548
549 mod = False
550 for name in file_to_change:
551 lines = open(name,'r').read().split('\n')
552 for iline, line in enumerate(lines):
553 result = comp_re.match(line)
554 if result:
555 if new != result.group(2) and '$' not in result.group(2):
556 mod = True
557 lines[iline] = result.group(1) + var + "=" + new
558 elif compiler_type == 'gfortran' and line.startswith('DEFAULT_F_COMPILER'):
559 lines[iline] = "DEFAULT_F_COMPILER = %s" % new
560 elif compiler_type == 'cpp' and line.startswith('DEFAULT_CPP_COMPILER'):
561 lines[iline] = "DEFAULT_CPP_COMPILER = %s" % new
562
563 if mod:
564 open(name,'w').write('\n'.join(lines))
565
566 mod = False
567
572 """mute_logger (designed to work as with statement),
573 files allow to redirect the output of the log to a given file.
574 """
575
576 - def __init__(self, names, levels, files=None, **opt):
577 assert isinstance(names, list)
578 assert isinstance(names, list)
579
580 self.names = names
581 self.levels = levels
582 if isinstance(files, list):
583 self.files = files
584 else:
585 self.files = [files] * len(names)
586 self.logger_saved_info = {}
587 self.opts = opt
588
599
600 - def __exit__(self, ctype, value, traceback ):
609
611 """ Setup the logger by redirecting them all to logfiles in tmp """
612
613 logs = full_logname.split('.')
614 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\
615 range(len(full_logname.split('.')))]
616 for logname in lognames:
617 try:
618 os.remove(path)
619 except Exception, error:
620 pass
621 my_logger = logging.getLogger(logname)
622 hdlr = logging.FileHandler(path)
623
624
625 self.logger_saved_info[logname] = [hdlr, my_logger.handlers]
626
627
628 for old_hdlr in list(my_logger.handlers):
629 my_logger.removeHandler(old_hdlr)
630 my_logger.addHandler(hdlr)
631
632 my_logger.debug('Log of %s' % logname)
633
635 """ Setup the logger by redirecting them all to logfiles in tmp """
636
637 logs = full_logname.split('.')
638 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\
639 range(len(full_logname.split('.')))]
640 for logname in lognames:
641 if path:
642 try:
643 os.remove(path)
644 except Exception, error:
645 pass
646 my_logger = logging.getLogger(logname)
647 if logname in self.logger_saved_info:
648 my_logger.removeHandler(self.logger_saved_info[logname][0])
649 for old_hdlr in self.logger_saved_info[logname][1]:
650 my_logger.addHandler(old_hdlr)
651 else:
652 my_logger.setLevel(level)
653
654
655
656
657 nb_open =0
660 """
661 A context manager to temporarily redirect stdout or stderr
662
663 e.g.:
664
665
666 with stdchannel_redirected(sys.stderr, os.devnull):
667 if compiler.has_function('clock_gettime', libraries=['rt']):
668 libraries.append('rt')
669 """
670
671 try:
672 oldstdchannel = os.dup(stdchannel.fileno())
673 dest_file = open(dest_filename, 'w')
674 os.dup2(dest_file.fileno(), stdchannel.fileno())
675 yield
676 finally:
677 if oldstdchannel is not None:
678 os.dup2(oldstdchannel, stdchannel.fileno())
679 os.close(oldstdchannel)
680 if dest_file is not None:
681 dest_file.close()
682
684 '''
685 return the number of open file descriptors for current process
686
687 .. warning: will only work on UNIX-like os-es.
688 '''
689 import subprocess
690 import os
691
692 pid = os.getpid()
693 procs = subprocess.check_output(
694 [ "lsof", '-w', '-Ff', "-p", str( pid ) ] )
695 nprocs = filter(
696 lambda s: s and s[ 0 ] == 'f' and s[1: ].isdigit(),
697 procs.split( '\n' ) )
698
699 return nprocs
700
702 """ Detects whether the specified C++ compiler is clang."""
703
704 try:
705 p = Popen([cpp_compiler, '--version'], stdout=subprocess.PIPE,
706 stderr=subprocess.PIPE)
707 output, error = p.communicate()
708 except Exception, error:
709
710 return False
711 return 'LLVM' in output
712
714 """ Detects if the specified c++ compiler will normally link against the C++
715 standard library -lc++ or -libstdc++."""
716
717 is_clang = detect_if_cpp_compiler_is_clang(cpp_compiler)
718 if is_clang:
719 try:
720 import platform
721 v, _,_ = platform.mac_ver()
722 if not v:
723
724
725 return '-lc++'
726 else:
727 v = float(v.rsplit('.')[1])
728 if v >= 9:
729 return '-lc++'
730 else:
731 return '-lstdc++'
732 except:
733 return '-lstdc++'
734 return '-lstdc++'
735
737 """find the current compiler for the current directory"""
738
739
740
741 if compiler_type == 'fortran':
742 comp = re.compile("^\s*FC\s*=\s*([\w\/\\.\-]+)\s*")
743 elif compiler_type == 'cpp':
744 comp = re.compile("^\s*CXX\s*=\s*([\w\/\\.\-]+)\s*")
745 else:
746 MadGraph5Error, 'Unknown compiler type: %s' % compiler_type
747
748 for line in open(path):
749 if comp.search(line):
750 compiler = comp.search(line).groups()[0]
751 return compiler
752 elif compiler_type == 'fortran' and line.startswith('DEFAULT_F_COMPILER'):
753 return line.split('=')[1].strip()
754 elif compiler_type == 'cpp' and line.startswith('DEFAULT_CPP_COMPILER'):
755 return line.split('=')[1].strip()
756
758 """ return a list of all file starting with makefile in the given directory"""
759
760 out=[]
761
762 if type(directory)==list:
763 for name in directory:
764 out+=find_makefile_in_dir(name)
765 return out
766
767
768 for name in os.listdir(directory):
769 if os.path.isdir(directory+'/'+name):
770 out+=find_makefile_in_dir(directory+'/'+name)
771 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('makefile'):
772 out.append(directory+'/'+name)
773 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('make_opt'):
774 out.append(directory+'/'+name)
775 return out
776
778
779
780 os.path.walk('.', rm_file_extension, '.o')
781
782
783 libraries = ['libblocks.a', 'libgeneric_mw.a', 'libMWPS.a', 'libtools.a', 'libdhelas3.a',
784 'libdsample.a', 'libgeneric.a', 'libmodel.a', 'libpdf.a', 'libdhelas3.so', 'libTF.a',
785 'libdsample.so', 'libgeneric.so', 'libmodel.so', 'libpdf.so']
786 lib_pos='./lib'
787 [os.remove(os.path.join(lib_pos, lib)) for lib in libraries \
788 if os.path.exists(os.path.join(lib_pos, lib))]
789
803
807
811 replace_dict = dict(key_values)
812 replacement_function = lambda match: replace_dict[match.group(0)]
813 pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M)
814 return lambda string: pattern.sub(replacement_function, string)
815
818
821 def deco_check(f):
822 def deco_f(arg, *args, **opt):
823 try:
824 return f(arg, *args, **opt)
825 except OSError, error:
826 logger.debug('try to recover from %s' % error)
827 if isinstance(arg, list):
828 prog = arg[0]
829 else:
830 prog = arg[0]
831
832
833 if error.errno == 13:
834 if os.path.exists(prog):
835 os.system('chmod +x %s' % prog)
836 elif 'cwd' in opt and opt['cwd'] and \
837 os.path.isfile(pjoin(opt['cwd'],arg[0])):
838 os.system('chmod +x %s' % pjoin(opt['cwd'],arg[0]))
839 return f(arg, *args, **opt)
840
841 elif error.errno == 2:
842
843 raise Exception, '%s fails with no such file or directory' \
844 % arg
845 else:
846 raise
847 return deco_f
848 return deco_check
849
850
851 @check_system_error()
852 -def call(arg, *args, **opt):
853 """nice way to call an external program with nice error treatment"""
854 try:
855 return subprocess.call(arg, *args, **opt)
856 except OSError:
857 arg[0] = './%s' % arg[0]
858 return subprocess.call(arg, *args, **opt)
859
860 @check_system_error()
861 -def Popen(arg, *args, **opt):
862 """nice way to call an external program with nice error treatment"""
863 return subprocess.Popen(arg, *args, **opt)
864
867 """try to open a file with multiple try to ensure that filesystem is sync"""
868 return open(filepath, *args, ** opt)
869
870
871
872
873
874 -def tail(f, n, offset=None):
875 """Reads a n lines from f with an offset of offset lines. The return
876 value is a tuple in the form ``lines``.
877 """
878 avg_line_length = 74
879 to_read = n + (offset or 0)
880
881 while 1:
882 try:
883 f.seek(-(avg_line_length * to_read), 2)
884 except IOError:
885
886
887 f.seek(0)
888 pos = f.tell()
889 lines = f.read().splitlines()
890 if len(lines) >= to_read or pos == 0:
891 return lines[-to_read:offset and -offset or None]
892 avg_line_length *= 1.3
893 avg_line_length = int(avg_line_length)
894
899 """return the last line of a file"""
900
901 return tail(fsock, 1)[0]
902
904 """read a file returning the lines in reverse order for each call of readline()
905 This actually just reads blocks (4096 bytes by default) of data from the end of
906 the file and returns last line in an internal buffer."""
907
908
910 """ readline in a backward way """
911
912 while len(self.data) == 1 and ((self.blkcount * self.blksize) < self.size):
913 self.blkcount = self.blkcount + 1
914 line = self.data[0]
915 try:
916 self.seek(-self.blksize * self.blkcount, 2)
917 self.data = (self.read(self.blksize) + line).split('\n')
918 except IOError:
919 self.seek(0)
920 data = self.read(self.size - (self.blksize * (self.blkcount-1))) + line
921 self.data = data.split('\n')
922
923 if len(self.data) == 0:
924 return ""
925
926 line = self.data.pop()
927 return line + '\n'
928
929 - def __init__(self, filepos, blksize=4096):
930 """initialize the internal structures"""
931
932
933 self.size = os.stat(filepos)[6]
934
935 self.blksize = blksize
936
937 self.blkcount = 1
938 file.__init__(self, filepos, 'rb')
939
940
941 if self.size > self.blksize:
942 self.seek(-self.blksize * self.blkcount, 2)
943 self.data = self.read(self.blksize).split('\n')
944
945
946 if not self.data[-1]:
947 self.data.pop()
948
950 line = self.readline()
951 if line:
952 return line
953 else:
954 raise StopIteration
955
971
985
991 """create a temporary directory and ensure this one to be cleaned.
992 """
993
994 - def __init__(self, suffix='', prefix='tmp', dir=None):
995 self.nb_try_remove = 0
996 import tempfile
997 self.path = tempfile.mkdtemp(suffix, prefix, dir)
998
999
1000 - def __exit__(self, ctype, value, traceback ):
1001
1002 if False and isinstance(value, Exception):
1003 sprint("Directory %s not cleaned. This directory can be removed manually" % self.path)
1004 return False
1005 try:
1006 shutil.rmtree(self.path)
1007 except OSError:
1008 self.nb_try_remove += 1
1009 if self.nb_try_remove < 3:
1010 time.sleep(10)
1011 self.__exit__(ctype, value, traceback)
1012 else:
1013 logger.warning("Directory %s not completely cleaned. This directory can be removed manually" % self.path)
1014
1017
1019 """create a temporary directory and ensure this one to be cleaned.
1020 """
1021
1022 - def __init__(self, cls, attribute, value):
1023
1024 self.old_value = getattr(cls, attribute)
1025 self.cls = cls
1026 self.attribute = attribute
1027 setattr(self.cls, self.attribute, value)
1028
1029 - def __exit__(self, ctype, value, traceback ):
1030
1031 setattr(self.cls, self.attribute, self.old_value)
1032
1034 return self.old_value
1035
1036
1037
1038
1039 -def gunzip(path, keep=False, stdout=None):
1040 """ a standard replacement for os.system('gunzip -f %s.gz ' % event_path)"""
1041
1042 if not path.endswith(".gz"):
1043 if os.path.exists("%s.gz" % path):
1044 path = "%s.gz" % path
1045 else:
1046 raise Exception, "%(path)s does not finish by .gz and the file %(path)s.gz does not exists" %\
1047 {"path": path}
1048
1049
1050
1051 if os.path.getsize(path) > 1e8:
1052 if stdout:
1053 os.system('gunzip -c %s > %s' % (path, stdout))
1054 else:
1055 os.system('gunzip %s' % path)
1056 return 0
1057
1058 if not stdout:
1059 stdout = path[:-3]
1060 try:
1061 gfile = ziplib.open(path, "r")
1062 except IOError:
1063 raise
1064 else:
1065 try:
1066 open(stdout,'w').write(gfile.read())
1067 except IOError:
1068
1069 if stdout == path:
1070 return
1071 else:
1072 files.cp(path, stdout)
1073
1074 if not keep:
1075 os.remove(path)
1076 return 0
1077
1078 -def gzip(path, stdout=None, error=True, forceexternal=False):
1079 """ a standard replacement for os.system('gzip %s ' % path)"""
1080
1081
1082 if os.path.getsize(path) > 1e9 or forceexternal:
1083 call(['gzip', '-f', path])
1084 if stdout:
1085 if not stdout.endswith(".gz"):
1086 stdout = "%s.gz" % stdout
1087 shutil.move('%s.gz' % path, stdout)
1088 return
1089
1090 if not stdout:
1091 stdout = "%s.gz" % path
1092 elif not stdout.endswith(".gz"):
1093 stdout = "%s.gz" % stdout
1094
1095 try:
1096 ziplib.open(stdout,"w").write(open(path).read())
1097 except OverflowError:
1098 gzip(path, stdout, error=error, forceexternal=True)
1099 except Exception:
1100 if error:
1101 raise
1102 else:
1103 os.remove(path)
1104
1109 """ a convinient class to open a file """
1110
1111 web_browser = None
1112 eps_viewer = None
1113 text_editor = None
1114 configured = False
1115
1117 """open a file"""
1118
1119
1120 if not self.configured:
1121 self.configure()
1122
1123 try:
1124 extension = filename.rsplit('.',1)[1]
1125 except IndexError:
1126 extension = ''
1127
1128
1129
1130 if extension in ['html','htm','php']:
1131 self.open_program(self.web_browser, filename, background=True)
1132 elif extension in ['ps','eps']:
1133 self.open_program(self.eps_viewer, filename, background=True)
1134 else:
1135 self.open_program(self.text_editor,filename, mac_check=False)
1136
1137
1138 @classmethod
1161
1162 @classmethod
1200
1201
1202 @staticmethod
1204 """find a valid shell program in the list"""
1205
1206 for p in possibility:
1207 if which(p):
1208 logger.info('Using default %s \"%s\". ' % (program, p) + \
1209 'Set another one in ./input/mg5_configuration.txt')
1210 return p
1211
1212 logger.info('No valid %s found. ' % program + \
1213 'Please set in ./input/mg5_configuration.txt')
1214 return None
1215
1216
1217 - def open_program(self, program, file_path, mac_check=True, background=False):
1218 """ open a file with a given program """
1219
1220 if mac_check==True and sys.platform == 'darwin':
1221 return self.open_mac_program(program, file_path)
1222
1223
1224 if program:
1225 arguments = program.split()
1226 arguments.append(file_path)
1227
1228 if not background:
1229 subprocess.call(arguments)
1230 else:
1231 import thread
1232 thread.start_new_thread(subprocess.call,(arguments,))
1233 else:
1234 logger.warning('Not able to open file %s since no program configured.' % file_path + \
1235 'Please set one in ./input/mg5_configuration.txt')
1236
1238 """ open a text with the text editor """
1239
1240 if not program:
1241
1242 os.system('open %s' % file_path)
1243 elif which(program):
1244
1245 arguments = program.split()
1246 arguments.append(file_path)
1247 subprocess.call(arguments)
1248 else:
1249
1250 os.system('open -a %s %s' % (program, file_path))
1251
1271
1273 """ Try and guess what shell type does the user use."""
1274 try:
1275 if os.environ['SHELL'].endswith('bash'):
1276 return 'bash'
1277 elif os.environ['SHELL'].endswith('tcsh'):
1278 return 'tcsh'
1279 else:
1280
1281 return None
1282 except KeyError:
1283 return None
1284
1286 """ check if a path is executable"""
1287 try:
1288 return os.access(path, os.X_OK)
1289 except Exception:
1290 return False
1291
1293 """Option Peaser which raise an error instead as calling exit"""
1294
1295 - def exit(self, status=0, msg=None):
1300
1302 """Returns the current line number in our program."""
1303
1304 if not __debug__:
1305 return
1306
1307 import inspect
1308 if opt.has_key('log'):
1309 log = opt['log']
1310 else:
1311 log = logging.getLogger('madgraph')
1312 if opt.has_key('level'):
1313 level = opt['level']
1314 else:
1315 level = logging.getLogger('madgraph').level
1316
1317
1318
1319
1320 lineno = inspect.currentframe().f_back.f_lineno
1321 fargs = inspect.getframeinfo(inspect.currentframe().f_back)
1322 filename, lineno = fargs[:2]
1323
1324
1325 try:
1326 source = inspect.getsourcelines(inspect.currentframe().f_back)
1327 line = source[0][lineno-source[1]]
1328 line = re.findall(r"misc\.sprint\(\s*(.*)\)\s*($|#)", line)[0][0]
1329 if line.startswith("'") and line.endswith("'") and line.count(",") ==0:
1330 line= ''
1331 elif line.startswith("\"") and line.endswith("\"") and line.count(",") ==0:
1332 line= ''
1333 elif line.startswith(("\"","'")) and len(args)==1 and "%" in line:
1334 line= ''
1335 except Exception:
1336 line=''
1337
1338 if line:
1339 intro = ' %s = \033[0m' % line
1340 else:
1341 intro = ''
1342
1343
1344 log.log(level, ' '.join([intro]+[str(a) for a in args]) + \
1345 ' \033[1;30m[%s at line %s]\033[0m' % (os.path.basename(filename), lineno))
1346 return
1347
1348
1349
1350
1351 -def equal(a,b,sig_fig=6, zero_limit=True):
1352 """function to check if two float are approximatively equal"""
1353 import math
1354
1355 if not a or not b:
1356 if zero_limit:
1357 power = sig_fig + 1
1358 else:
1359 return a == b
1360 else:
1361 power = sig_fig - int(math.log10(abs(a))) + 1
1362
1363 return ( a==b or abs(int(a*10**power) - int(b*10**power)) < 10)
1364
1365
1366
1367
1368
1369
1370
1371 -class chdir:
1373 self.newPath = newPath
1374
1376 self.savedPath = os.getcwd()
1377 os.chdir(self.newPath)
1378
1379 - def __exit__(self, etype, value, traceback):
1380 os.chdir(self.savedPath)
1381
1382
1383
1384
1385
1386 -def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
1387 '''This function will spwan a thread and run the given function using the args, kwargs and
1388 return the given default value if the timeout_duration is exceeded
1389 '''
1390 import threading
1391 class InterruptableThread(threading.Thread):
1392 def __init__(self):
1393 threading.Thread.__init__(self)
1394 self.result = default
1395 def run(self):
1396 try:
1397 self.result = func(*args, **kwargs)
1398 except Exception,error:
1399 print error
1400 self.result = default
1401 it = InterruptableThread()
1402 it.start()
1403 it.join(timeout_duration)
1404 return it.result
1405
1406
1407
1408
1409
1410 -class digest:
1411
1413 try:
1414 return self.test_hashlib()
1415 except Exception:
1416 pass
1417 try:
1418 return self.test_md5()
1419 except Exception:
1420 pass
1421 try:
1422 return self.test_zlib()
1423 except Exception:
1424 pass
1425
1427 import hashlib
1428 def digest(text):
1429 """using mg5 for the hash"""
1430 t = hashlib.md5()
1431 t.update(text)
1432 return t.hexdigest()
1433 return digest
1434
1436 import md5
1437 def digest(text):
1438 """using mg5 for the hash"""
1439 t = md5.md5()
1440 t.update(text)
1441 return t.hexdigest()
1442 return digest
1443
1445 import zlib
1446 def digest(text):
1447 return zlib.adler32(text)
1448
1449 digest = digest().test_all()
1456 self.cmd_args = args
1457 self.cmd_opts = opts
1458 self.execution_state = False
1459
1461 self.max_vms_memory = 0
1462 self.max_rss_memory = 0
1463
1464 self.t1 = None
1465 self.t0 = time.time()
1466 self.p = subprocess.Popen(*self.cmd_args,**self.cmd_opts)
1467 self.execution_state = True
1468
1470 if not self.check_execution_state():
1471 return False
1472
1473 self.t1 = time.time()
1474
1475
1476
1477 flash = subprocess.Popen("ps -p %i -o rss"%self.p.pid,
1478 shell=True,stdout=subprocess.PIPE,stderr=open(os.devnull,"w"))
1479 stdout_list = flash.communicate()[0].split('\n')
1480 rss_memory = int(stdout_list[1])
1481
1482 vms_memory = 0
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511 self.max_vms_memory = max(self.max_vms_memory,vms_memory)
1512 self.max_rss_memory = max(self.max_rss_memory,rss_memory)
1513
1514 return self.check_execution_state()
1515
1517
1518
1519 return self.p.poll() == None
1520
1522 if not self.execution_state:
1523 return False
1524 if self.is_running():
1525 return True
1526 self.executation_state = False
1527 self.t1 = time.time()
1528 return False
1529
1530 - def close(self,kill=False):
1531
1532 if self.p.poll() == None:
1533 if kill:
1534 self.p.kill()
1535 else:
1536 self.p.terminate()
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549 try:
1550 import Foundation
1551 import objc
1552 NSUserNotification = objc.lookUpClass('NSUserNotification')
1553 NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')
1556 try:
1557 notification = NSUserNotification.alloc().init()
1558 notification.setTitle_('MadGraph5_aMC@NLO')
1559 notification.setSubtitle_(subtitle)
1560 notification.setInformativeText_(info_text)
1561 notification.setUserInfo_(userInfo)
1562 NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
1563 except:
1564 pass
1565 except:
1568