Package madgraph :: Package interface :: Module extended_cmd
[hide private]
[frames] | no frames]

Source Code for Module madgraph.interface.extended_cmd

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2011 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  """  A file containing different extension of the cmd basic python library""" 
  16   
  17   
  18  import cmd 
  19  import logging 
  20  import os 
  21  import pydoc 
  22  import re 
  23  import signal 
  24  import subprocess 
  25  import sys 
  26  import traceback 
  27  try: 
  28      import readline 
  29      GNU_SPLITTING = ('GNU' in readline.__doc__) 
  30  except: 
  31      readline = None 
  32      GNU_SPLITTING = True 
  33   
  34   
  35  logger = logging.getLogger('cmdprint') # for stdout 
  36  logger_stderr = logging.getLogger('fatalerror') # for stderr 
  37   
  38  try: 
  39      import madgraph.various.misc as misc 
  40      from madgraph import MG5DIR 
  41      MADEVENT = False 
  42  except ImportError, error: 
  43      try: 
  44          import internal.misc as misc 
  45      except: 
  46          raise error 
  47      MADEVENT = True 
  48   
  49   
  50  pjoin = os.path.join 
51 52 -class TimeOutError(Exception):
53 """Class for run-time error"""
54
55 -def debug(debug_only=True):
56 57 def deco_debug(f): 58 59 if debug_only and not __debug__: 60 return f 61 62 def deco_f(*args, **opt): 63 try: 64 return f(*args, **opt) 65 except Exception, error: 66 logger.error(error) 67 logger.error(traceback.print_exc(file=sys.stdout)) 68 return
69 return deco_f 70 return deco_debug 71
72 73 #=============================================================================== 74 # CmdExtended 75 #=============================================================================== 76 -class BasicCmd(cmd.Cmd):
77 """Simple extension for the readline""" 78
79 - def preloop(self):
80 if readline and not 'libedit' in readline.__doc__: 81 readline.set_completion_display_matches_hook(self.print_suggestions)
82
83 - def deal_multiple_categories(self, dico, forceCategory=False):
84 """convert the multiple category in a formatted list understand by our 85 specific readline parser""" 86 87 if 'libedit' in readline.__doc__: 88 # No parser in this case, just send all the valid options 89 out = [] 90 for name, opt in dico.items(): 91 out += opt 92 return out 93 94 # check if more than one categories but only one value: 95 if not forceCategory and all(len(s) <= 1 for s in dico.values() ): 96 values = set((s[0] for s in dico.values() if len(s)==1)) 97 if len(values) == 1: 98 return values 99 100 # That's the real work 101 out = [] 102 valid=0 103 # if the key starts with number order the key with that number. 104 for name, opt in dico.items(): 105 if not opt: 106 continue 107 name = name.replace(' ', '_') 108 valid += 1 109 out.append(opt[0].rstrip()+'@@'+name+'@@') 110 # Remove duplicate 111 d = {} 112 for x in opt: 113 d[x] = 1 114 opt = list(d.keys()) 115 opt.sort() 116 out += opt 117 118 if not forceCategory and valid == 1: 119 out = out[1:] 120 121 return out
122 123 @debug()
124 - def print_suggestions(self, substitution, matches, longest_match_length) :
125 """print auto-completions by category""" 126 if not hasattr(self, 'completion_prefix'): 127 self.completion_prefix = '' 128 longest_match_length += len(self.completion_prefix) 129 try: 130 if len(matches) == 1: 131 self.stdout.write(matches[0]+' ') 132 return 133 self.stdout.write('\n') 134 l2 = [a[-2:] for a in matches] 135 if '@@' in l2: 136 nb_column = self.getTerminalSize()//(longest_match_length+1) 137 pos=0 138 for val in self.completion_matches: 139 if val.endswith('@@'): 140 category = val.rsplit('@@',2)[1] 141 category = category.replace('_',' ') 142 self.stdout.write('\n %s:\n%s\n' % (category, '=' * (len(category)+2))) 143 start = 0 144 pos = 0 145 continue 146 elif pos and pos % nb_column ==0: 147 self.stdout.write('\n') 148 self.stdout.write(self.completion_prefix + val + \ 149 ' ' * (longest_match_length +1 -len(val))) 150 pos +=1 151 self.stdout.write('\n') 152 else: 153 # nb column 154 nb_column = self.getTerminalSize()//(longest_match_length+1) 155 for i,val in enumerate(matches): 156 if i and i%nb_column ==0: 157 self.stdout.write('\n') 158 self.stdout.write(self.completion_prefix + val + \ 159 ' ' * (longest_match_length +1 -len(val))) 160 self.stdout.write('\n') 161 162 self.stdout.write(self.prompt+readline.get_line_buffer()) 163 self.stdout.flush() 164 except Exception, error: 165 if __debug__: 166 logger.error(error)
167
168 - def getTerminalSize(self):
169 def ioctl_GWINSZ(fd): 170 try: 171 import fcntl, termios, struct 172 cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, 173 '1234')) 174 except Exception: 175 return None 176 return cr
177 cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) 178 if not cr: 179 try: 180 fd = os.open(os.ctermid(), os.O_RDONLY) 181 cr = ioctl_GWINSZ(fd) 182 os.close(fd) 183 except Exception: 184 pass 185 if not cr: 186 try: 187 cr = (os.environ['LINES'], os.environ['COLUMNS']) 188 except Exception: 189 cr = (25, 80) 190 return int(cr[1])
191
192 - def complete(self, text, state):
193 """Return the next possible completion for 'text'. 194 If a command has not been entered, then complete against command list. 195 Otherwise try to call complete_<command> to get list of completions. 196 """ 197 198 if state == 0: 199 import readline 200 origline = readline.get_line_buffer() 201 line = origline.lstrip() 202 stripped = len(origline) - len(line) 203 begidx = readline.get_begidx() - stripped 204 endidx = readline.get_endidx() - stripped 205 206 if ';' in line: 207 begin, line = line.rsplit(';',1) 208 begidx = begidx - len(begin) - 1 209 endidx = endidx - len(begin) - 1 210 if line[:begidx] == ' ' * begidx: 211 begidx=0 212 213 if begidx>0: 214 cmd, args, foo = self.parseline(line) 215 if cmd == '': 216 compfunc = self.completedefault 217 else: 218 try: 219 compfunc = getattr(self, 'complete_' + cmd) 220 except AttributeError: 221 compfunc = self.completedefault 222 else: 223 compfunc = self.completenames 224 225 # correct wrong splittion with '\ ' 226 if line and begidx > 2 and line[begidx-2:begidx] == '\ ': 227 Ntext = line.split(os.path.sep)[-1] 228 self.completion_prefix = Ntext.rsplit('\ ', 1)[0] + '\ ' 229 to_rm = len(self.completion_prefix) - 1 230 Nbegidx = len(line.rsplit(os.path.sep, 1)[0]) + 1 231 data = compfunc(Ntext.replace('\ ', ' '), line, Nbegidx, endidx) 232 self.completion_matches = [p[to_rm:] for p in data 233 if len(p)>to_rm] 234 # correct wrong splitting with '-' 235 elif line and line[begidx-1] == '-': 236 try: 237 Ntext = line.split()[-1] 238 self.completion_prefix = Ntext.rsplit('-',1)[0] +'-' 239 to_rm = len(self.completion_prefix) 240 Nbegidx = len(line.rsplit(None, 1)[0]) 241 data = compfunc(Ntext, line, Nbegidx, endidx) 242 self.completion_matches = [p[to_rm:] for p in data 243 if len(p)>to_rm] 244 except Exception, error: 245 print error 246 else: 247 self.completion_prefix = '' 248 self.completion_matches = compfunc(text, line, begidx, endidx) 249 250 self.completion_matches = [ l if l[-1] in [' ','@','=',os.path.sep] 251 else ((l + ' ') if not l.endswith('\\$') else l[:-2]) 252 for l in self.completion_matches if l] 253 254 try: 255 return self.completion_matches[state] 256 except IndexError, error: 257 # if __debug__: 258 # logger.error('\n Completion ERROR:') 259 # logger.error( error) 260 return None
261 262 @staticmethod
263 - def split_arg(line):
264 """Split a line of arguments""" 265 266 split = line.split() 267 out=[] 268 tmp='' 269 for data in split: 270 if data[-1] == '\\': 271 tmp += data[:-1]+' ' 272 elif tmp: 273 tmp += data 274 tmp = os.path.expanduser(os.path.expandvars(tmp)) 275 out.append(tmp) 276 else: 277 out.append(data) 278 return out
279 280 @staticmethod
281 - def list_completion(text, list, line=''):
282 """Propose completions of text in list""" 283 284 if not text: 285 completions = list 286 else: 287 completions = [ f 288 for f in list 289 if f.startswith(text) 290 ] 291 292 return completions
293 294 295 @staticmethod
296 - def path_completion(text, base_dir = None, only_dirs = False, 297 relative=True):
298 """Propose completions of text to compose a valid path""" 299 300 if base_dir is None: 301 base_dir = os.getcwd() 302 base_dir = os.path.expanduser(os.path.expandvars(base_dir)) 303 304 if text == '~': 305 text = '~/' 306 prefix, text = os.path.split(text) 307 prefix = os.path.expanduser(os.path.expandvars(prefix)) 308 base_dir = os.path.join(base_dir, prefix) 309 if prefix: 310 prefix += os.path.sep 311 312 if only_dirs: 313 completion = [prefix + f 314 for f in os.listdir(base_dir) 315 if f.startswith(text) and \ 316 os.path.isdir(os.path.join(base_dir, f)) and \ 317 (not f.startswith('.') or text.startswith('.')) 318 ] 319 else: 320 completion = [ prefix + f 321 for f in os.listdir(base_dir) 322 if f.startswith(text) and \ 323 os.path.isfile(os.path.join(base_dir, f)) and \ 324 (not f.startswith('.') or text.startswith('.')) 325 ] 326 327 completion = completion + \ 328 [prefix + f + os.path.sep 329 for f in os.listdir(base_dir) 330 if f.startswith(text) and \ 331 os.path.isdir(os.path.join(base_dir, f)) and \ 332 (not f.startswith('.') or text.startswith('.')) 333 ] 334 335 if relative: 336 completion += [prefix + f for f in ['.'+os.path.sep, '..'+os.path.sep] if \ 337 f.startswith(text) and not prefix.startswith('.')] 338 339 completion = [a.replace(' ','\ ') for a in completion] 340 return completion
341
342 343 344 345 -class CheckCmd(object):
346 """Extension of the cmd object for only the check command""" 347
348 - def check_history(self, args):
349 """check the validity of line""" 350 351 if len(args) > 1: 352 self.help_history() 353 raise self.InvalidCmd('\"history\" command takes at most one argument') 354 355 if not len(args): 356 return 357 358 if args[0] =='.': 359 if not self._export_dir: 360 raise self.InvalidCmd("No default directory is defined for \'.\' option") 361 elif args[0] != 'clean': 362 dirpath = os.path.dirname(args[0]) 363 if dirpath and not os.path.exists(dirpath) or \ 364 os.path.isdir(args[0]): 365 raise self.InvalidCmd("invalid path %s " % dirpath)
366
367 - def check_save(self, args):
368 """check that the line is compatible with save options""" 369 370 if len(args) > 2: 371 self.help_save() 372 raise self.InvalidCmd, 'too many arguments for save command.' 373 374 if len(args) == 2: 375 if args[0] != 'options': 376 self.help_save() 377 raise self.InvalidCmd, '\'%s\' is not recognized as first argument.' % \ 378 args[0] 379 else: 380 args.pop(0)
381
382 -class HelpCmd(object):
383 """Extension of the cmd object for only the help command""" 384
385 - def help_quit(self):
386 logger.info("-- terminates the application",'$MG:color:BLUE') 387 logger.info("syntax: quit",'$MG:color:BLACK')
388 389 help_EOF = help_quit 390
391 - def help_history(self):
392 logger.info("-- interact with the command history.",'$MG:color:BLUE') 393 logger.info("syntax: history [FILEPATH|clean|.] ",'$MG:color:BLACK') 394 logger.info(" > If FILEPATH is \'.\' and \'output\' is done,") 395 logger.info(" Cards/proc_card_mg5.dat will be used.") 396 logger.info(" > If FILEPATH is omitted, the history will be output to stdout.") 397 logger.info(" \"clean\" will remove all entries from the history.")
398
399 - def help_help(self):
400 logger.info("-- access to the in-line help",'$MG:color:BLUE') 401 logger.info("syntax: help",'$MG:color:BLACK')
402
403 - def help_save(self):
404 """help text for save""" 405 logger.info("-- save options configuration to filepath.",'$MG:color:BLUE') 406 logger.info("syntax: save [options] [FILEPATH]",'$MG:color:BLACK')
407
408 - def help_display(self):
409 """help for display command""" 410 logger.info("-- display a the status of various internal state variables",'$MG:color:BLUE') 411 logger.info("syntax: display " + "|".join(self._display_opts),'$MG:color:BLACK')
412
413 -class CompleteCmd(object):
414 """Extension of the cmd object for only the complete command""" 415
416 - def complete_display(self,text, line, begidx, endidx):
417 args = self.split_arg(line[0:begidx]) 418 # Format 419 if len(args) == 1: 420 return self.list_completion(text, self._display_opts)
421
422 - def complete_history(self, text, line, begidx, endidx):
423 "Complete the history command" 424 425 args = self.split_arg(line[0:begidx]) 426 427 # Directory continuation 428 if args[-1].endswith(os.path.sep): 429 return self.path_completion(text, 430 os.path.join('.',*[a for a in args \ 431 if a.endswith(os.path.sep)])) 432 433 if len(args) == 1: 434 return self.path_completion(text)
435
436 - def complete_save(self, text, line, begidx, endidx):
437 "Complete the save command" 438 439 args = self.split_arg(line[0:begidx]) 440 441 # Format 442 if len(args) == 1: 443 return self.list_completion(text, ['options']) 444 445 # Directory continuation 446 if args[-1].endswith(os.path.sep): 447 return self.path_completion(text, 448 pjoin('.',*[a for a in args if a.endswith(os.path.sep)]), 449 only_dirs = True) 450 451 # Filename if directory is not given 452 if len(args) == 2: 453 return self.path_completion(text)
454
455 -class Cmd(CheckCmd, HelpCmd, CompleteCmd, BasicCmd):
456 """Extension of the cmd.Cmd command line. 457 This extensions supports line breaking, history, comments, 458 internal call to cmdline, path completion,... 459 this class should be MG5 independent""" 460 461 #suggested list of command 462 next_possibility = {} # command : [list of suggested command] 463 history_header = "" 464 465 _display_opts = ['options','variable'] 466 allow_notification_center = True 467
468 - class InvalidCmd(Exception):
469 """expected error for wrong command""" 470 pass
471 472 ConfigurationError = InvalidCmd 473 474 debug_output = 'debug' 475 error_debug = """Please report this bug to developers\n 476 More information is found in '%(debug)s'.\n 477 Please attach this file to your report.""" 478 config_debug = error_debug 479 480 keyboard_stop_msg = """stopping all current operation 481 in order to quit the program please enter exit""" 482 483
484 - def __init__(self, *arg, **opt):
485 """Init history and line continuation""" 486 487 self.log = True 488 self.history = [] 489 self.save_line = '' # for line splitting 490 cmd.Cmd.__init__(self, *arg, **opt) 491 self.__initpos = os.path.abspath(os.getcwd()) 492 self.child = None # sub CMD interface call from this one 493 self.mother = None #This CMD interface was called from another one 494 self.inputfile = None # input file (in non interactive mode) 495 self.haspiping = not sys.stdin.isatty() # check if mg5 is piped 496 self.stored_line = '' # for be able to treat answer to question in input file 497 # answer which are not required. 498 if not hasattr(self, 'helporder'): 499 self.helporder = ['Documented commands']
500 501
502 - def no_notification(self):
503 """avoid to have html opening / notification""" 504 self.allow_notification_center = False 505 try: 506 self.options['automatic_html_opening'] = False 507 self.options['notification_center'] = False 508 509 except: 510 pass
511 512
513 - def precmd(self, line):
514 """ A suite of additional function needed for in the cmd 515 this implement history, line breaking, comment treatment,... 516 """ 517 518 if not line: 519 return line 520 line = line.lstrip() 521 522 # Check if we are continuing a line: 523 if self.save_line: 524 line = self.save_line + line 525 self.save_line = '' 526 527 # Check if the line is complete 528 if line.endswith('\\'): 529 self.save_line = line[:-1] 530 return '' # do nothing 531 532 # Remove comment 533 if '#' in line: 534 line = line.split('#')[0] 535 536 # Deal with line splitting 537 if ';' in line: 538 lines = line.split(';') 539 for subline in lines: 540 if not (subline.startswith("history") or subline.startswith('help') \ 541 or subline.startswith('#*')): 542 self.history.append(subline) 543 stop = self.onecmd(subline) 544 stop = self.postcmd(stop, subline) 545 return '' 546 547 # execute the line command 548 self.history.append(line) 549 return line
550
551 - def postcmd(self,stop, line):
552 """ finishing a command 553 This looks if the command add a special post part.""" 554 555 if line.strip(): 556 try: 557 cmd, subline = line.split(None, 1) 558 except ValueError: 559 pass 560 else: 561 if hasattr(self,'post_%s' %cmd): 562 stop = getattr(self, 'post_%s' % cmd)(stop, subline) 563 return stop
564
565 - def define_child_cmd_interface(self, obj_instance, interface=True):
566 """Define a sub cmd_interface""" 567 568 # We are in a file reading mode. So we need to redirect the cmd 569 self.child = obj_instance 570 self.child.mother = self 571 572 #ensure that notification are sync: 573 self.child.allow_notification_center = self.allow_notification_center 574 575 if self.use_rawinput and interface: 576 # We are in interactive mode -> simply call the child 577 obj_instance.cmdloop() 578 stop = obj_instance.postloop() 579 return stop 580 if self.inputfile: 581 # we are in non interactive mode -> so pass the line information 582 obj_instance.inputfile = self.inputfile 583 584 obj_instance.haspiping = self.haspiping 585 586 if not interface: 587 return self.child
588 589 #=============================================================================== 590 # Ask a question with nice options handling 591 #===============================================================================
592 - def ask(self, question, default, choices=[], path_msg=None, 593 timeout = True, fct_timeout=None, ask_class=None, alias={}, 594 first_cmd=None, **opt):
595 """ ask a question with some pre-define possibility 596 path info is 597 """ 598 599 if path_msg: 600 path_msg = [path_msg] 601 else: 602 path_msg = [] 603 604 if timeout: 605 try: 606 timeout = self.options['timeout'] 607 except Exception: 608 pass 609 610 # add choice info to the question 611 if choices + path_msg: 612 question += ' [' 613 question += "\033[%dm%s\033[0m, " % (4, default) 614 for data in choices[:9] + path_msg: 615 if default == data: 616 continue 617 else: 618 question += "%s, " % data 619 620 if len(choices) > 9: 621 question += '... , ' 622 question = question[:-2]+']' 623 else: 624 question += "[\033[%dm%s\033[0m] " % (4, default) 625 if ask_class: 626 obj = ask_class 627 elif path_msg: 628 obj = OneLinePathCompletion 629 else: 630 obj = SmartQuestion 631 632 if alias: 633 choices += alias.keys() 634 635 question_instance = obj(question, allow_arg=choices, default=default, 636 mother_interface=self, **opt) 637 638 if first_cmd: 639 question_instance.onecmd(first_cmd) 640 641 if not self.haspiping: 642 if hasattr(obj, "haspiping"): 643 obj.haspiping = self.haspiping 644 645 646 647 648 answer = self.check_answer_in_input_file(question_instance, default, path_msg) 649 if answer is not None: 650 if answer in alias: 651 answer = alias[answer] 652 if ask_class: 653 answer = question_instance.default(answer) 654 return answer 655 656 question = question_instance.question 657 value = Cmd.timed_input(question, default, timeout=timeout, 658 fct=question_instance, fct_timeout=fct_timeout) 659 660 661 662 try: 663 if value in alias: 664 value = alias[value] 665 except TypeError: 666 pass 667 if value == default and ask_class: 668 value = question_instance.default(default) 669 return value
670
671 - def do_import(self, line):
672 """Advanced commands: Import command files""" 673 674 args = self.split_arg(line) 675 # Check argument's validity 676 self.check_import(args) 677 678 # Execute the card 679 self.import_command_file(args[1])
680
681 - def check_import(self, args):
682 """check import command""" 683 684 if '-f' in args: 685 self.force = True 686 args.remove('-f') 687 if args[0] != 'command': 688 args.set(0, 'command') 689 if len(args) != 2: 690 raise self.InvalidCmd('import command requires one filepath argument') 691 if not os.path.exists(args[1]): 692 raise 'No such file or directory %s' % args[1]
693 694
695 - def check_answer_in_input_file(self, question_instance, default, path=False):
696 """Questions can have answer in output file (or not)""" 697 698 if not self.inputfile: 699 return None# interactive mode 700 701 line = self.get_stored_line() 702 # line define if a previous answer was not answer correctly 703 if not line: 704 try: 705 line = self.inputfile.next() 706 except StopIteration: 707 if self.haspiping: 708 logger.debug('piping') 709 self.store_line(line) 710 return None # print the question and use the pipe 711 logger.info(question_instance.question) 712 logger.warning('The answer to the previous question is not set in your input file') 713 logger.warning('Use %s value' % default) 714 return str(default) 715 716 line = line.replace('\n','').strip() 717 if '#' in line: 718 line = line.split('#')[0] 719 if not line: 720 # Comment or empty line, pass to the next one 721 return self.check_answer_in_input_file(question_instance, default, path) 722 options = question_instance.allow_arg 723 if line in options: 724 return line 725 elif hasattr(question_instance, 'do_%s' % line.split()[0]): 726 #This is a command line, exec it and check next line 727 logger.info(line) 728 fct = getattr(question_instance, 'do_%s' % line.split()[0]) 729 fct(' '.join(line.split()[1:])) 730 return self.check_answer_in_input_file(question_instance, default, path) 731 elif path: 732 line = os.path.expanduser(os.path.expandvars(line)) 733 if os.path.isfile(line): 734 return line 735 # No valid answer provides 736 if self.haspiping: 737 self.store_line(line) 738 return None # print the question and use the pipe 739 else: 740 logger.info(question_instance.question) 741 logger.warning('The answer to the previous question is not set in your input file') 742 logger.warning('Use %s value' % default) 743 self.store_line(line) 744 return str(default)
745
746 - def store_line(self, line):
747 """store a line of the input file which should be executed by the higher mother""" 748 749 if self.mother: 750 self.mother.store_line(line) 751 else: 752 self.stored_line = line
753
754 - def get_stored_line(self):
755 """return stored line and clean it""" 756 if self.mother: 757 value = self.mother.get_stored_line() 758 self.mother.stored_line = None 759 else: 760 value = self.stored_line 761 self.stored_line = None 762 return value
763 764 765
766 - def nice_error_handling(self, error, line):
767 """ """ 768 # Make sure that we are at the initial position 769 if self.child: 770 return self.child.nice_error_handling(error, line) 771 772 os.chdir(self.__initpos) 773 # Create the debug files 774 self.log = False 775 if os.path.exists(self.debug_output): 776 os.remove(self.debug_output) 777 try: 778 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output.replace(' ', '\ ')) 779 except Exception, error: 780 logger.error(error) 781 782 debug_file = open(self.debug_output, 'a') 783 traceback.print_exc(file=debug_file) 784 # Create a nice error output 785 if self.history and line == self.history[-1]: 786 error_text = 'Command \"%s\" interrupted with error:\n' % line 787 elif self.history: 788 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line 789 error_text += '\"%s\" with error:\n' % self.history[-1] 790 else: 791 error_text = '' 792 error_text += '%s : %s\n' % (error.__class__.__name__, 793 str(error).replace('\n','\n\t')) 794 error_text += self.error_debug % {'debug':self.debug_output} 795 logger_stderr.critical(error_text) 796 797 798 # Add options status to the debug file 799 try: 800 self.do_display('options', debug_file) 801 except Exception, error: 802 debug_file.write('Fail to write options with error %s' % error) 803 804 #add the cards: 805 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']: 806 try: 807 ff = open(pjoin(self.me_dir, 'Cards', card)) 808 debug_file.write(ff.read()) 809 ff.close() 810 except Exception: 811 pass 812 813 #stop the execution if on a non interactive mode 814 if self.use_rawinput == False: 815 return True 816 return False
817 818 819
820 - def nice_user_error(self, error, line):
821 if self.child: 822 return self.child.nice_user_error(error, line) 823 # Make sure that we are at the initial position 824 os.chdir(self.__initpos) 825 if line == self.history[-1]: 826 error_text = 'Command \"%s\" interrupted with error:\n' % line 827 else: 828 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line 829 error_text += '\"%s\" with error:\n' % self.history[-1] 830 error_text += '%s : %s' % (error.__class__.__name__, 831 str(error).replace('\n','\n\t')) 832 logger_stderr.error(error_text) 833 #stop the execution if on a non interactive mode 834 if self.use_rawinput == False: 835 return True 836 # Remove failed command from history 837 self.history.pop() 838 return False
839
840 - def nice_config_error(self, error, line):
841 if self.child: 842 return self.child.nice_user_error(error, line) 843 # Make sure that we are at the initial position 844 os.chdir(self.__initpos) 845 if not self.history or line == self.history[-1]: 846 error_text = 'Error detected in \"%s\"\n' % line 847 else: 848 error_text = 'Error detected in sub-command %s\n' % self.history[-1] 849 error_text += 'write debug file %s \n' % self.debug_output 850 self.log = False 851 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output) 852 debug_file = open(self.debug_output, 'a') 853 traceback.print_exc(file=debug_file) 854 error_text += self.config_debug % {'debug' :self.debug_output} 855 error_text += '%s : %s' % (error.__class__.__name__, 856 str(error).replace('\n','\n\t')) 857 logger_stderr.error(error_text) 858 859 # Add options status to the debug file 860 try: 861 self.do_display('options', debug_file) 862 except Exception, error: 863 debug_file.write('Fail to write options with error %s' % error) 864 #stop the execution if on a non interactive mode 865 if self.use_rawinput == False: 866 return True 867 # Remove failed command from history 868 if self.history: 869 self.history.pop() 870 return False
871
872 - def onecmd_orig(self, line, **opt):
873 """Interpret the argument as though it had been typed in response 874 to the prompt. 875 876 The return value is a flag indicating whether interpretation of 877 commands by the interpreter should stop. 878 879 This allow to pass extra argument for internal call. 880 """ 881 if '~/' in line and os.environ.has_key('HOME'): 882 line = line.replace('~/', '%s/' % os.environ['HOME']) 883 line = os.path.expandvars(line) 884 cmd, arg, line = self.parseline(line) 885 if not line: 886 return self.emptyline() 887 if cmd is None: 888 return self.default(line) 889 self.lastcmd = line 890 if cmd == '': 891 return self.default(line) 892 else: 893 try: 894 func = getattr(self, 'do_' + cmd) 895 except AttributeError: 896 return self.default(line) 897 return func(arg, **opt)
898 899
900 - def onecmd(self, line, **opt):
901 """catch all error and stop properly command accordingly""" 902 903 me_dir = '' 904 if hasattr(self, 'me_dir'): 905 me_dir = os.path.basename(me_dir) + ' ' 906 907 try: 908 return self.onecmd_orig(line, **opt) 909 except self.InvalidCmd as error: 910 if __debug__: 911 self.nice_error_handling(error, line) 912 self.history.pop() 913 else: 914 self.nice_user_error(error, line) 915 if self.allow_notification_center: 916 misc.apple_notify('Run %sfailed' % me_dir, 917 'Invalid Command: %s' % error.__class__.__name__) 918 919 except self.ConfigurationError as error: 920 self.nice_config_error(error, line) 921 if self.allow_notification_center: 922 misc.apple_notify('Run %sfailed' % me_dir, 923 'Configuration error') 924 except Exception as error: 925 self.nice_error_handling(error, line) 926 if self.mother: 927 self.do_quit('') 928 if self.allow_notification_center: 929 misc.apple_notify('Run %sfailed' % me_dir, 930 'Exception: %s' % error.__class__.__name__) 931 except KeyboardInterrupt as error: 932 self.stop_on_keyboard_stop() 933 if __debug__: 934 self.nice_config_error(error, line) 935 logger.error(self.keyboard_stop_msg)
936
937 - def stop_on_keyboard_stop(self):
938 """action to perform to close nicely on a keyboard interupt""" 939 pass # dummy function
940
941 - def exec_cmd(self, line, errorhandling=False, printcmd=True, 942 precmd=False, postcmd=True, **opt):
943 """for third party call, call the line with pre and postfix treatment 944 without global error handling """ 945 946 if printcmd and not line.startswith('#'): 947 logger.info(line) 948 if self.child: 949 current_interface = self.child 950 else: 951 current_interface = self 952 953 if precmd: 954 line = current_interface.precmd(line) 955 if errorhandling: 956 stop = current_interface.onecmd(line, **opt) 957 else: 958 stop = Cmd.onecmd_orig(current_interface, line, **opt) 959 if postcmd: 960 stop = current_interface.postcmd(stop, line) 961 return stop
962
963 - def run_cmd(self, line):
964 """for third party call, call the line with pre and postfix treatment 965 with global error handling""" 966 967 return self.exec_cmd(line, errorhandling=True, precmd=True)
968
969 - def emptyline(self):
970 """If empty line, do nothing. Default is repeat previous command.""" 971 pass
972
973 - def default(self, line, log=True):
974 """Default action if line is not recognized""" 975 976 # Faulty command 977 if log: 978 logger.warning("Command \"%s\" not recognized, please try again" % \ 979 line.split()[0]) 980 if line.strip() in ['q', '.q', 'stop']: 981 logger.info("If you want to quit mg5 please type \"exit\".") 982 983 if self.history and self.history[-1] == line: 984 self.history.pop()
985 986 987 988 989 990 # Write the list of command line use in this session
991 - def do_history(self, line):
992 """write in a file the suite of command that was used""" 993 994 args = self.split_arg(line) 995 # Check arguments validity 996 self.check_history(args) 997 998 if len(args) == 0: 999 logger.info('\n'.join(self.history)) 1000 return 1001 elif args[0] == 'clean': 1002 self.history = [] 1003 logger.info('History is cleaned') 1004 return 1005 elif args[0] == '.': 1006 output_file = os.path.join(self._export_dir, 'Cards', \ 1007 'proc_card_mg5.dat') 1008 output_file = open(output_file, 'w') 1009 else: 1010 output_file = open(args[0], 'w') 1011 1012 # Create the command file 1013 text = self.get_history_header() 1014 text += ('\n'.join(self.history) + '\n') 1015 1016 #write this information in a file 1017 output_file.write(text) 1018 output_file.close() 1019 1020 if self.log: 1021 logger.info("History written to " + output_file.name)
1022
1023 - def compile(self, *args, **opts):
1024 """ """ 1025 1026 return misc.compile(nb_core=self.options['nb_core'], *args, **opts)
1027
1028 - def avoid_history_duplicate(self, line, no_break=[]):
1029 """remove all line in history (but the last) starting with line. 1030 up to the point when a line didn't start by something in no_break. 1031 (reading in reverse order)""" 1032 1033 new_history = [] 1034 for i in range(1, len(self.history)+1): 1035 cur_line = self.history[-i] 1036 if i == 1: 1037 new_history.append(cur_line) 1038 elif not any((cur_line.startswith(text) for text in no_break)): 1039 to_add = self.history[:-i+1] 1040 to_add.reverse() 1041 new_history += to_add 1042 break 1043 elif cur_line.startswith(line): 1044 continue 1045 else: 1046 new_history.append(cur_line) 1047 1048 new_history.reverse() 1049 self.history[:] = new_history
1050 1051
1052 - def import_command_file(self, filepath):
1053 # remove this call from history 1054 if self.history: 1055 self.history.pop() 1056 1057 #avoid that command of other file interfere with this one. 1058 previous_store_line = self.get_stored_line() 1059 1060 # Read the lines of the file and execute them 1061 if isinstance(filepath, str): 1062 commandline = open(filepath).readlines() 1063 else: 1064 commandline = filepath 1065 oldinputfile = self.inputfile 1066 oldraw = self.use_rawinput 1067 self.inputfile = (l for l in commandline) # make a generator 1068 self.use_rawinput = False 1069 # Note using "for line in open(filepath)" is not safe since the file 1070 # filepath can be overwritten during the run (leading to weird results) 1071 # Note also that we need a generator and not a list. 1072 for line in self.inputfile: 1073 #remove pointless spaces and \n 1074 line = line.replace('\n', '').strip() 1075 # execute the line 1076 if line: 1077 self.exec_cmd(line, precmd=True) 1078 stored = self.get_stored_line() 1079 while stored: 1080 line = stored 1081 self.exec_cmd(line, precmd=True) 1082 stored = self.get_stored_line() 1083 1084 # If a child was open close it 1085 if self.child: 1086 self.child.exec_cmd('quit') 1087 self.inputfile = oldinputfile 1088 self.use_rawinput = oldraw 1089 1090 # restore original store line 1091 cmd = self 1092 while hasattr(cmd, 'mother') and cmd.mother: 1093 cmd = cmd.mother 1094 cmd.stored_line = previous_store_line 1095 return
1096
1097 - def get_history_header(self):
1098 """Default history header""" 1099 1100 return self.history_header
1101
1102 - def postloop(self):
1103 """ """ 1104 1105 args = self.split_arg(self.lastcmd) 1106 if args and args[0] in ['quit','exit']: 1107 if 'all' in args: 1108 return True 1109 if len(args) >1 and args[1].isdigit(): 1110 if args[1] not in ['0', '1']: 1111 return True 1112 return False
1113 1114 #=============================================================================== 1115 # Ask a question with a maximum amount of time to answer 1116 #=============================================================================== 1117 @staticmethod
1118 - def timed_input(question, default, timeout=None, noerror=True, fct=None, 1119 fct_timeout=None):
1120 """ a question with a maximal time to answer take default otherwise""" 1121 1122 def handle_alarm(signum, frame): 1123 raise TimeOutError
1124 1125 signal.signal(signal.SIGALRM, handle_alarm) 1126 1127 if fct is None: 1128 fct = raw_input 1129 1130 if timeout: 1131 signal.alarm(timeout) 1132 question += '[%ss to answer] ' % (timeout) 1133 try: 1134 result = fct(question) 1135 except TimeOutError: 1136 if noerror: 1137 logger.info('\nuse %s' % default) 1138 if fct_timeout: 1139 fct_timeout(True) 1140 return default 1141 else: 1142 signal.alarm(0) 1143 raise 1144 finally: 1145 signal.alarm(0) 1146 if fct_timeout: 1147 fct_timeout(False) 1148 return result
1149 1150 1151 1152 1153 1154 1155 # Quit
1156 - def do_quit(self, line):
1157 """Not in help: exit the mainloop() """ 1158 1159 if self.child: 1160 self.child.exec_cmd('quit ' + line, printcmd=False) 1161 return 1162 elif self.mother: 1163 self.mother.child = None 1164 if line == 'all': 1165 pass 1166 elif line: 1167 level = int(line) - 1 1168 if level: 1169 self.mother.lastcmd = 'quit %s' % level 1170 logger.info(' ') 1171 return True
1172 1173 # Aliases 1174 do_EOF = do_quit 1175 do_exit = do_quit 1176
1177 - def do_help(self, line):
1178 """Not in help: propose some usefull possible action """ 1179 1180 # if they are an argument use the default help 1181 if line: 1182 return cmd.Cmd.do_help(self, line) 1183 1184 1185 names = self.get_names() 1186 cmds = {} 1187 names.sort() 1188 # There can be duplicates if routines overridden 1189 prevname = '' 1190 for name in names: 1191 if name[:3] == 'do_': 1192 if name == prevname: 1193 continue 1194 prevname = name 1195 cmdname=name[3:] 1196 try: 1197 doc = getattr(self.cmd, name).__doc__ 1198 except Exception: 1199 doc = None 1200 if not doc: 1201 doc = getattr(self, name).__doc__ 1202 if not doc: 1203 tag = "Documented commands" 1204 elif ':' in doc: 1205 tag = doc.split(':',1)[0] 1206 else: 1207 tag = "Documented commands" 1208 if tag in cmds: 1209 cmds[tag].append(cmdname) 1210 else: 1211 cmds[tag] = [cmdname] 1212 1213 self.stdout.write("%s\n"%str(self.doc_leader)) 1214 for tag in self.helporder: 1215 if tag not in cmds: 1216 continue 1217 header = "%s (type help <topic>):" % tag 1218 self.print_topics(header, cmds[tag], 15,80) 1219 for name, item in cmds.items(): 1220 if name in self.helporder: 1221 continue 1222 if name == "Not in help": 1223 continue 1224 header = "%s (type help <topic>):" % name 1225 self.print_topics(header, item, 15,80) 1226 1227 1228 ## Add contextual help 1229 if len(self.history) == 0: 1230 last_action_2 = last_action = 'start' 1231 else: 1232 last_action_2 = last_action = 'none' 1233 1234 pos = 0 1235 authorize = self.next_possibility.keys() 1236 while last_action_2 not in authorize and last_action not in authorize: 1237 pos += 1 1238 if pos > len(self.history): 1239 last_action_2 = last_action = 'start' 1240 break 1241 1242 args = self.history[-1 * pos].split() 1243 last_action = args[0] 1244 if len(args)>1: 1245 last_action_2 = '%s %s' % (last_action, args[1]) 1246 else: 1247 last_action_2 = 'none' 1248 1249 logger.info('Contextual Help') 1250 logger.info('===============') 1251 if last_action_2 in authorize: 1252 options = self.next_possibility[last_action_2] 1253 elif last_action in authorize: 1254 options = self.next_possibility[last_action] 1255 else: 1256 return 1257 text = 'The following command(s) may be useful in order to continue.\n' 1258 for option in options: 1259 text+='\t %s \n' % option 1260 logger.info(text)
1261
1262 - def do_display(self, line, output=sys.stdout):
1263 """Advanced commands: basic display""" 1264 1265 args = self.split_arg(line) 1266 #check the validity of the arguments 1267 1268 if len(args) == 0: 1269 self.help_display() 1270 raise self.InvalidCmd, 'display require at least one argument' 1271 1272 if args[0] == "options": 1273 outstr = "Value of current Options:\n" 1274 for key, value in self.options.items(): 1275 outstr += '%25s \t:\t%s\n' %(key,value) 1276 output.write(outstr) 1277 1278 elif args[0] == "variable": 1279 outstr = "Value of Internal Variable:\n" 1280 try: 1281 var = eval(args[1]) 1282 except Exception: 1283 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1] 1284 else: 1285 outstr += 'GLOBAL:\n' 1286 outstr += misc.nice_representation(var, nb_space=4) 1287 1288 try: 1289 var = eval('self.%s' % args[1]) 1290 except Exception: 1291 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1] 1292 else: 1293 outstr += 'LOCAL:\n' 1294 outstr += misc.nice_representation(var, nb_space=4) 1295 split = args[1].split('.') 1296 for i, name in enumerate(split): 1297 try: 1298 __import__('.'.join(split[:i+1])) 1299 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1]))) 1300 except ImportError: 1301 try: 1302 var = eval(args[1]) 1303 except Exception, error: 1304 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1] 1305 break 1306 else: 1307 outstr += 'EXTERNAL:\n' 1308 outstr += misc.nice_representation(var, nb_space=4) 1309 else: 1310 var = eval(args[1]) 1311 outstr += 'EXTERNAL:\n' 1312 outstr += misc.nice_representation(var, nb_space=4) 1313 1314 pydoc.pager(outstr)
1315 1316
1317 - def do_save(self, line, check=True):
1318 """Save the configuration file""" 1319 1320 args = self.split_arg(line) 1321 # Check argument validity 1322 if check: 1323 Cmd.check_save(self, args) 1324 1325 # find base file for the configuration 1326 if'HOME' in os.environ and os.environ['HOME'] and \ 1327 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')): 1328 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt') 1329 if hasattr(self, 'me_dir'): 1330 basedir = self.me_dir 1331 elif not MADEVENT: 1332 basedir = MG5DIR 1333 else: 1334 basedir = os.getcwd() 1335 elif MADEVENT: 1336 # launch via ./bin/madevent 1337 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']: 1338 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)): 1339 base = pjoin(self.me_dir, 'Cards', config_file) 1340 basedir = self.me_dir 1341 else: 1342 if hasattr(self, 'me_dir'): 1343 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 1344 if len(args) == 0 and os.path.exists(base): 1345 self.write_configuration(base, base, self.me_dir) 1346 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 1347 basedir = MG5DIR 1348 1349 if len(args) == 0: 1350 args.append(base) 1351 self.write_configuration(args[0], base, basedir, self.options)
1352
1353 - def write_configuration(self, filepath, basefile, basedir, to_keep):
1354 """Write the configuration file""" 1355 # We use the default configuration file as a template. 1356 # to ensure that all configuration information are written we 1357 # keep track of all key that we need to write. 1358 1359 logger.info('save configuration file to %s' % filepath) 1360 to_write = to_keep.keys() 1361 text = "" 1362 # Use local configuration => Need to update the path 1363 for line in file(basefile): 1364 if '=' in line: 1365 data, value = line.split('=',1) 1366 else: 1367 text += line 1368 continue 1369 data = data.strip() 1370 if data.startswith('#'): 1371 key = data[1:].strip() 1372 else: 1373 key = data 1374 if '#' in value: 1375 value, comment = value.split('#',1) 1376 else: 1377 comment = '' 1378 if key in to_keep: 1379 value = str(to_keep[key]) 1380 else: 1381 text += line 1382 continue 1383 try: 1384 to_write.remove(key) 1385 except Exception: 1386 pass 1387 if '_path' in key: 1388 # special case need to update path 1389 # check if absolute path 1390 if not os.path.isabs(value): 1391 value = os.path.realpath(os.path.join(basedir, value)) 1392 text += '%s = %s # %s \n' % (key, value, comment) 1393 for key in to_write: 1394 if key in to_keep: 1395 text += '%s = %s \n' % (key, to_keep[key]) 1396 1397 if not MADEVENT: 1398 text += """\n# MG5 MAIN DIRECTORY\n""" 1399 text += "mg5_path = %s\n" % MG5DIR 1400 1401 writer = open(filepath,'w') 1402 writer.write(text) 1403 writer.close()
1404
1405 1406 1407 1408 -class CmdShell(Cmd):
1409 """CMD command with shell activate""" 1410 1411 # Access to shell
1412 - def do_shell(self, line):
1413 "Run a shell command" 1414 1415 if line.strip() is '': 1416 self.help_shell() 1417 else: 1418 logging.info("running shell command: " + line) 1419 subprocess.call(line, shell=True)
1420
1421 - def complete_shell(self, text, line, begidx, endidx):
1422 """ add path for shell """ 1423 1424 # Filename if directory is given 1425 # 1426 if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep: 1427 if not text: 1428 text = '' 1429 output = self.path_completion(text, 1430 base_dir=\ 1431 self.split_arg(line[0:begidx])[-1]) 1432 else: 1433 output = self.path_completion(text) 1434 return output
1435
1436 - def help_shell(self):
1437 """help for the shell""" 1438 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE') 1439 logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
1440
1441 1442 1443 1444 #=============================================================================== 1445 # Question with auto-completion 1446 #=============================================================================== 1447 -class SmartQuestion(BasicCmd):
1448 """ a class for answering a question with the path autocompletion""" 1449
1450 - def preloop(self):
1451 """Initializing before starting the main loop""" 1452 self.prompt = '>' 1453 self.value = None 1454 BasicCmd.preloop(self)
1455 1456
1457 - def __init__(self, question, allow_arg=[], default=None, 1458 mother_interface=None, *arg, **opt):
1459 self.question = question 1460 self.wrong_answer = 0 # forbids infinite loop 1461 self.allow_arg = [str(a) for a in allow_arg] 1462 self.history_header = '' 1463 self.default_value = str(default) 1464 self.mother_interface = mother_interface 1465 cmd.Cmd.__init__(self, *arg, **opt)
1466
1467 - def __call__(self, question, reprint_opt=True, **opts):
1468 1469 self.question = question 1470 for key,value in opts: 1471 setattr(self, key, value) 1472 if reprint_opt: 1473 print question 1474 return self.cmdloop()
1475 1476
1477 - def completenames(self, text, line, *ignored):
1478 prev_timer = signal.alarm(0) # avoid timer if any 1479 if prev_timer: 1480 nb_back = len(line) 1481 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1482 self.stdout.write(line) 1483 self.stdout.flush() 1484 try: 1485 out = {} 1486 out[' Options'] = Cmd.list_completion(text, self.allow_arg) 1487 out[' Recognized command'] = BasicCmd.completenames(self, text) 1488 1489 return self.deal_multiple_categories(out) 1490 except Exception, error: 1491 print error
1492
1493 - def get_names(self):
1494 # This method used to pull in base class attributes 1495 # at a time dir() didn't do it yet. 1496 return dir(self)
1497
1498 - def onecmd(self, line, **opt):
1499 """catch all error and stop properly command accordingly 1500 Interpret the argument as though it had been typed in response 1501 to the prompt. 1502 1503 The return value is a flag indicating whether interpretation of 1504 commands by the interpreter should stop. 1505 1506 This allow to pass extra argument for internal call. 1507 """ 1508 try: 1509 if '~/' in line and os.environ.has_key('HOME'): 1510 line = line.replace('~/', '%s/' % os.environ['HOME']) 1511 line = os.path.expandvars(line) 1512 cmd, arg, line = self.parseline(line) 1513 if not line: 1514 return self.emptyline() 1515 if cmd is None: 1516 return self.default(line) 1517 self.lastcmd = line 1518 if cmd == '': 1519 return self.default(line) 1520 else: 1521 try: 1522 func = getattr(self, 'do_' + cmd) 1523 except AttributeError: 1524 return self.default(line) 1525 return func(arg, **opt) 1526 except Exception as error: 1527 logger.warning(error)
1528
1529 - def reask(self, reprint_opt=True):
1530 pat = re.compile('\[(\d*)s to answer\]') 1531 prev_timer = signal.alarm(0) # avoid timer if any 1532 1533 if prev_timer: 1534 if pat.search(self.question): 1535 timeout = int(pat.search(self.question).groups()[0]) 1536 else: 1537 timeout=20 1538 print 1539 signal.alarm(timeout) 1540 if reprint_opt: 1541 if not prev_timer: 1542 self.question = pat.sub('',self.question) 1543 print self.question 1544 return False
1545
1546 - def default(self, line):
1547 """Default action if line is not recognized""" 1548 1549 if line.strip() == '' and self.default_value is not None: 1550 self.value = self.default_value 1551 else: 1552 self.value = line
1553
1554 - def emptyline(self):
1555 """If empty line, return default""" 1556 1557 if self.default_value is not None: 1558 self.value = self.default_value
1559 1560
1561 - def postcmd(self, stop, line):
1562 1563 try: 1564 if self.value in self.allow_arg: 1565 return True 1566 elif str(self.value) == 'EOF': 1567 self.value = self.default_value 1568 return True 1569 elif line and hasattr(self, 'do_%s' % line.split()[0]): 1570 return self.reask() 1571 elif self.value == 'repeat': 1572 return self.reask() 1573 elif len(self.allow_arg)==0: 1574 return True 1575 else: 1576 raise Exception 1577 except Exception,error: 1578 if self.wrong_answer < 100: 1579 self.wrong_answer += 1 1580 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \ 1581 % (self.value,','.join(self.allow_arg))) 1582 logger.warning('please retry') 1583 return False 1584 else: 1585 self.value = self.default_value 1586 return True
1587
1588 - def cmdloop(self, intro=None):
1589 cmd.Cmd.cmdloop(self, intro) 1590 return self.value
1591
1592 # a function helper 1593 -def smart_input(input_text, allow_arg=[], default=None):
1594 print input_text 1595 obj = SmartQuestion(allow_arg=allow_arg, default=default) 1596 return obj.cmdloop()
1597
1598 #=============================================================================== 1599 # Question in order to return a path with auto-completion 1600 #=============================================================================== 1601 -class OneLinePathCompletion(SmartQuestion):
1602 """ a class for answering a question with the path autocompletion""" 1603 1604 completion_prefix='' 1605
1606 - def completenames(self, text, line, begidx, endidx):
1607 prev_timer = signal.alarm(0) # avoid timer if any 1608 if prev_timer: 1609 nb_back = len(line) 1610 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1611 self.stdout.write(line) 1612 self.stdout.flush() 1613 1614 try: 1615 out = {} 1616 out[' Options'] = Cmd.list_completion(text, self.allow_arg) 1617 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False) 1618 out[' Recognized command'] = BasicCmd.completenames(self, text) 1619 1620 return self.deal_multiple_categories(out) 1621 except Exception, error: 1622 print error
1623
1624 - def precmd(self, *args):
1625 """ """ 1626 1627 signal.alarm(0) 1628 return SmartQuestion.precmd(self, *args)
1629
1630 - def completedefault(self,text, line, begidx, endidx):
1631 prev_timer = signal.alarm(0) # avoid timer if any 1632 if prev_timer: 1633 nb_back = len(line) 1634 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1635 self.stdout.write(line) 1636 self.stdout.flush() 1637 try: 1638 args = Cmd.split_arg(line[0:begidx]) 1639 except Exception, error: 1640 print error 1641 1642 # Directory continuation 1643 if args[-1].endswith(os.path.sep): 1644 1645 return Cmd.path_completion(text, 1646 os.path.join('.',*[a for a in args \ 1647 if a.endswith(os.path.sep)])) 1648 self.completenames(line+text)
1649 1650
1651 - def postcmd(self, stop, line):
1652 try: 1653 if self.value in self.allow_arg: 1654 return True 1655 elif self.value and os.path.isfile(self.value): 1656 return os.path.relpath(self.value) 1657 elif self.value and str(self.value) == 'EOF': 1658 self.value = self.default_value 1659 return True 1660 elif line and hasattr(self, 'do_%s' % line.split()[0]): 1661 # go to retry 1662 reprint_opt = True 1663 elif self.value == 'repeat': 1664 reprint_opt = True 1665 else: 1666 raise Exception 1667 except Exception, error: 1668 print """not valid argument. Valid argument are file path or value in (%s).""" \ 1669 % ','.join(self.allow_arg) 1670 print 'please retry' 1671 reprint_opt = False 1672 1673 return self.reask(reprint_opt)
1674
1675 1676 # a function helper 1677 -def raw_path_input(input_text, allow_arg=[], default=None):
1678 print input_text 1679 obj = OneLinePathCompletion(allow_arg=allow_arg, default=default ) 1680 return obj.cmdloop()
1681
1682 #=============================================================================== 1683 # 1684 #=============================================================================== 1685 -class CmdFile(file):
1686 """ a class for command input file -in order to debug cmd \n problem""" 1687
1688 - def __init__(self, name, opt='rU'):
1689 1690 file.__init__(self, name, opt) 1691 self.text = file.read(self) 1692 self.close() 1693 self.lines = self.text.split('\n')
1694
1695 - def readline(self, *arg, **opt):
1696 """readline method treating correctly a line whithout \n at the end 1697 (add it) 1698 """ 1699 if self.lines: 1700 line = self.lines.pop(0) 1701 else: 1702 return '' 1703 1704 if line.endswith('\n'): 1705 return line 1706 else: 1707 return line + '\n'
1708
1709 - def __next__(self):
1710 return self.lines.__next__()
1711
1712 - def __iter__(self):
1713 return self.lines.__iter__()
1714