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):
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 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 119 if valid == 1: 120 out = out[1:] 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
467 - class InvalidCmd(Exception):
468 """expected error for wrong command""" 469 pass
470 471 ConfigurationError = InvalidCmd 472 473 debug_output = 'debug' 474 error_debug = """Please report this bug to developers\n 475 More information is found in '%(debug)s'.\n 476 Please attach this file to your report.""" 477 config_debug = error_debug 478 479 keyboard_stop_msg = """stopping all current operation 480 in order to quit the program please enter exit""" 481 482
483 - def __init__(self, *arg, **opt):
484 """Init history and line continuation""" 485 486 self.log = True 487 self.history = [] 488 self.save_line = '' # for line splitting 489 cmd.Cmd.__init__(self, *arg, **opt) 490 self.__initpos = os.path.abspath(os.getcwd()) 491 self.child = None # sub CMD interface call from this one 492 self.mother = None #This CMD interface was called from another one 493 self.inputfile = None # input file (in non interactive mode) 494 self.haspiping = not sys.stdin.isatty() # check if mg5 is piped 495 self.stored_line = '' # for be able to treat answer to question in input file 496 # answer which are not required. 497 if not hasattr(self, 'helporder'): 498 self.helporder = ['Documented commands']
499 500
501 - def precmd(self, line):
502 """ A suite of additional function needed for in the cmd 503 this implement history, line breaking, comment treatment,... 504 """ 505 506 if not line: 507 return line 508 line = line.lstrip() 509 510 # Check if we are continuing a line: 511 if self.save_line: 512 line = self.save_line + line 513 self.save_line = '' 514 515 # Check if the line is complete 516 if line.endswith('\\'): 517 self.save_line = line[:-1] 518 return '' # do nothing 519 520 # Remove comment 521 if '#' in line: 522 line = line.split('#')[0] 523 524 # Deal with line splitting 525 if ';' in line: 526 lines = line.split(';') 527 for subline in lines: 528 if not (subline.startswith("history") or subline.startswith('help') \ 529 or subline.startswith('#*')): 530 self.history.append(subline) 531 stop = self.onecmd(subline) 532 stop = self.postcmd(stop, subline) 533 return '' 534 535 # execute the line command 536 self.history.append(line) 537 return line
538
539 - def postcmd(self,stop, line):
540 """ finishing a command 541 This looks if the command add a special post part.""" 542 543 if line.strip(): 544 try: 545 cmd, subline = line.split(None, 1) 546 except ValueError: 547 pass 548 else: 549 if hasattr(self,'post_%s' %cmd): 550 stop = getattr(self, 'post_%s' % cmd)(stop, subline) 551 return stop
552
553 - def define_child_cmd_interface(self, obj_instance, interface=True):
554 """Define a sub cmd_interface""" 555 556 # We are in a file reading mode. So we need to redirect the cmd 557 self.child = obj_instance 558 self.child.mother = self 559 560 if self.use_rawinput and interface: 561 # We are in interactive mode -> simply call the child 562 obj_instance.cmdloop() 563 stop = obj_instance.postloop() 564 return stop 565 if self.inputfile: 566 # we are in non interactive mode -> so pass the line information 567 obj_instance.inputfile = self.inputfile 568 569 obj_instance.haspiping = self.haspiping 570 571 if not interface: 572 return self.child
573 574 #=============================================================================== 575 # Ask a question with nice options handling 576 #===============================================================================
577 - def ask(self, question, default, choices=[], path_msg=None, 578 timeout = True, fct_timeout=None, ask_class=None, alias={}, 579 first_cmd=None, **opt):
580 """ ask a question with some pre-define possibility 581 path info is 582 """ 583 584 if path_msg: 585 path_msg = [path_msg] 586 else: 587 path_msg = [] 588 589 if timeout: 590 try: 591 timeout = self.options['timeout'] 592 except Exception: 593 pass 594 595 # add choice info to the question 596 if choices + path_msg: 597 question += ' [' 598 question += "\033[%dm%s\033[0m, " % (4, default) 599 for data in choices[:9] + path_msg: 600 if default == data: 601 continue 602 else: 603 question += "%s, " % data 604 605 if len(choices) > 9: 606 question += '... , ' 607 question = question[:-2]+']' 608 else: 609 question += "[\033[%dm%s\033[0m] " % (4, default) 610 if ask_class: 611 obj = ask_class 612 elif path_msg: 613 obj = OneLinePathCompletion 614 else: 615 obj = SmartQuestion 616 617 if alias: 618 choices += alias.keys() 619 620 question_instance = obj(question, allow_arg=choices, default=default, 621 mother_interface=self, **opt) 622 623 if first_cmd: 624 question_instance.onecmd(first_cmd) 625 626 if not self.haspiping: 627 if hasattr(obj, "haspiping"): 628 obj.haspiping = self.haspiping 629 630 631 632 633 answer = self.check_answer_in_input_file(question_instance, default, path_msg) 634 if answer is not None: 635 if answer in alias: 636 answer = alias[answer] 637 if ask_class: 638 answer = question_instance.default(answer) 639 return answer 640 641 question = question_instance.question 642 value = Cmd.timed_input(question, default, timeout=timeout, 643 fct=question_instance, fct_timeout=fct_timeout) 644 645 646 647 try: 648 if value in alias: 649 value = alias[value] 650 except TypeError: 651 pass 652 if value == default and ask_class: 653 value = question_instance.default(default) 654 return value
655
656 - def do_import(self, line):
657 """Advanced commands: Import command files""" 658 659 args = self.split_arg(line) 660 # Check argument's validity 661 self.check_import(args) 662 663 # Execute the card 664 self.import_command_file(args[1])
665
666 - def check_import(self, args):
667 """check import command""" 668 669 if '-f' in args: 670 self.force = True 671 args.remove('-f') 672 if args[0] != 'command': 673 args.set(0, 'command') 674 if len(args) != 2: 675 raise self.InvalidCmd('import command requires one filepath argument') 676 if not os.path.exists(args[1]): 677 raise 'No such file or directory %s' % args[1]
678 679
680 - def check_answer_in_input_file(self, question_instance, default, path=False):
681 """Questions can have answer in output file (or not)""" 682 683 if not self.inputfile: 684 return None# interactive mode 685 686 line = self.get_stored_line() 687 # line define if a previous answer was not answer correctly 688 if not line: 689 try: 690 line = self.inputfile.next() 691 except StopIteration: 692 if self.haspiping: 693 logger.debug('piping') 694 self.store_line(line) 695 return None # print the question and use the pipe 696 logger.info(question_instance.question) 697 logger.warning('The answer to the previous question is not set in your input file') 698 logger.warning('Use %s value' % default) 699 return str(default) 700 701 line = line.replace('\n','').strip() 702 if '#' in line: 703 line = line.split('#')[0] 704 if not line: 705 # Comment or empty line, pass to the next one 706 return self.check_answer_in_input_file(question_instance, default, path) 707 options = question_instance.allow_arg 708 if line in options: 709 return line 710 elif hasattr(question_instance, 'do_%s' % line.split()[0]): 711 #This is a command line, exec it and check next line 712 logger.info(line) 713 fct = getattr(question_instance, 'do_%s' % line.split()[0]) 714 fct(' '.join(line.split()[1:])) 715 return self.check_answer_in_input_file(question_instance, default, path) 716 elif path: 717 line = os.path.expanduser(os.path.expandvars(line)) 718 if os.path.isfile(line): 719 return line 720 # No valid answer provides 721 if self.haspiping: 722 self.store_line(line) 723 return None # print the question and use the pipe 724 else: 725 logger.info(question_instance.question) 726 logger.warning('The answer to the previous question is not set in your input file') 727 logger.warning('Use %s value' % default) 728 self.store_line(line) 729 return str(default)
730
731 - def store_line(self, line):
732 """store a line of the input file which should be executed by the higher mother""" 733 734 if self.mother: 735 self.mother.store_line(line) 736 else: 737 self.stored_line = line
738
739 - def get_stored_line(self):
740 """return stored line and clean it""" 741 if self.mother: 742 value = self.mother.get_stored_line() 743 self.mother.stored_line = None 744 else: 745 value = self.stored_line 746 self.stored_line = None 747 return value
748 749 750
751 - def nice_error_handling(self, error, line):
752 """ """ 753 # Make sure that we are at the initial position 754 if self.child: 755 return self.child.nice_error_handling(error, line) 756 757 os.chdir(self.__initpos) 758 # Create the debug files 759 self.log = False 760 if os.path.exists(self.debug_output): 761 os.remove(self.debug_output) 762 try: 763 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output.replace(' ', '\ ')) 764 except Exception, error: 765 logger.error(error) 766 767 debug_file = open(self.debug_output, 'a') 768 traceback.print_exc(file=debug_file) 769 # Create a nice error output 770 if self.history and line == self.history[-1]: 771 error_text = 'Command \"%s\" interrupted with error:\n' % line 772 elif self.history: 773 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line 774 error_text += '\"%s\" with error:\n' % self.history[-1] 775 else: 776 error_text = '' 777 error_text += '%s : %s\n' % (error.__class__.__name__, 778 str(error).replace('\n','\n\t')) 779 error_text += self.error_debug % {'debug':self.debug_output} 780 logger_stderr.critical(error_text) 781 782 783 # Add options status to the debug file 784 try: 785 self.do_display('options', debug_file) 786 except Exception, error: 787 debug_file.write('Fail to write options with error %s' % error) 788 789 #add the cards: 790 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']: 791 try: 792 ff = open(pjoin(self.me_dir, 'Cards', card)) 793 debug_file.write(ff.read()) 794 ff.close() 795 except Exception: 796 pass 797 798 #stop the execution if on a non interactive mode 799 if self.use_rawinput == False: 800 return True 801 return False
802 803 804
805 - def nice_user_error(self, error, line):
806 if self.child: 807 return self.child.nice_user_error(error, line) 808 # Make sure that we are at the initial position 809 os.chdir(self.__initpos) 810 if line == self.history[-1]: 811 error_text = 'Command \"%s\" interrupted with error:\n' % line 812 else: 813 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line 814 error_text += '\"%s\" with error:\n' % self.history[-1] 815 error_text += '%s : %s' % (error.__class__.__name__, 816 str(error).replace('\n','\n\t')) 817 logger_stderr.error(error_text) 818 #stop the execution if on a non interactive mode 819 if self.use_rawinput == False: 820 return True 821 # Remove failed command from history 822 self.history.pop() 823 return False
824
825 - def nice_config_error(self, error, line):
826 if self.child: 827 return self.child.nice_user_error(error, line) 828 # Make sure that we are at the initial position 829 os.chdir(self.__initpos) 830 if not self.history or line == self.history[-1]: 831 error_text = 'Error detected in \"%s\"\n' % line 832 else: 833 error_text = 'Error detected in sub-command %s\n' % self.history[-1] 834 error_text += 'write debug file %s \n' % self.debug_output 835 self.log = False 836 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output) 837 debug_file = open(self.debug_output, 'a') 838 traceback.print_exc(file=debug_file) 839 error_text += self.config_debug % {'debug' :self.debug_output} 840 error_text += '%s : %s' % (error.__class__.__name__, 841 str(error).replace('\n','\n\t')) 842 logger_stderr.error(error_text) 843 844 # Add options status to the debug file 845 try: 846 self.do_display('options', debug_file) 847 except Exception, error: 848 debug_file.write('Fail to write options with error %s' % error) 849 #stop the execution if on a non interactive mode 850 if self.use_rawinput == False: 851 return True 852 # Remove failed command from history 853 if self.history: 854 self.history.pop() 855 return False
856
857 - def onecmd_orig(self, line, **opt):
858 """Interpret the argument as though it had been typed in response 859 to the prompt. 860 861 The return value is a flag indicating whether interpretation of 862 commands by the interpreter should stop. 863 864 This allow to pass extra argument for internal call. 865 """ 866 if '~/' in line and os.environ.has_key('HOME'): 867 line = line.replace('~/', '%s/' % os.environ['HOME']) 868 line = os.path.expandvars(line) 869 cmd, arg, line = self.parseline(line) 870 if not line: 871 return self.emptyline() 872 if cmd is None: 873 return self.default(line) 874 self.lastcmd = line 875 if cmd == '': 876 return self.default(line) 877 else: 878 try: 879 func = getattr(self, 'do_' + cmd) 880 except AttributeError: 881 return self.default(line) 882 return func(arg, **opt)
883 884
885 - def onecmd(self, line, **opt):
886 """catch all error and stop properly command accordingly""" 887 888 try: 889 return self.onecmd_orig(line, **opt) 890 except self.InvalidCmd as error: 891 if __debug__: 892 self.nice_error_handling(error, line) 893 self.history.pop() 894 else: 895 self.nice_user_error(error, line) 896 except self.ConfigurationError as error: 897 self.nice_config_error(error, line) 898 except Exception as error: 899 self.nice_error_handling(error, line) 900 if self.mother: 901 self.do_quit('') 902 except KeyboardInterrupt as error: 903 self.stop_on_keyboard_stop() 904 if __debug__: 905 self.nice_config_error(error, line) 906 logger.error(self.keyboard_stop_msg)
907
908 - def stop_on_keyboard_stop(self):
909 """action to perform to close nicely on a keyboard interupt""" 910 pass # dummy function
911
912 - def exec_cmd(self, line, errorhandling=False, printcmd=True, 913 precmd=False, postcmd=True, **opt):
914 """for third party call, call the line with pre and postfix treatment 915 without global error handling """ 916 917 if printcmd and not line.startswith('#'): 918 logger.info(line) 919 if self.child: 920 current_interface = self.child 921 else: 922 current_interface = self 923 924 if precmd: 925 line = current_interface.precmd(line) 926 if errorhandling: 927 stop = current_interface.onecmd(line, **opt) 928 else: 929 stop = Cmd.onecmd_orig(current_interface, line, **opt) 930 if postcmd: 931 stop = current_interface.postcmd(stop, line) 932 return stop
933
934 - def run_cmd(self, line):
935 """for third party call, call the line with pre and postfix treatment 936 with global error handling""" 937 938 return self.exec_cmd(line, errorhandling=True, precmd=True)
939
940 - def emptyline(self):
941 """If empty line, do nothing. Default is repeat previous command.""" 942 pass
943
944 - def default(self, line, log=True):
945 """Default action if line is not recognized""" 946 947 # Faulty command 948 if log: 949 logger.warning("Command \"%s\" not recognized, please try again" % \ 950 line.split()[0]) 951 if line.strip() in ['q', '.q', 'stop']: 952 logger.info("If you want to quit mg5 please type \"exit\".") 953 954 if self.history and self.history[-1] == line: 955 self.history.pop()
956 957 958 959 960 961 # Write the list of command line use in this session
962 - def do_history(self, line):
963 """write in a file the suite of command that was used""" 964 965 args = self.split_arg(line) 966 # Check arguments validity 967 self.check_history(args) 968 969 if len(args) == 0: 970 logger.info('\n'.join(self.history)) 971 return 972 elif args[0] == 'clean': 973 self.history = [] 974 logger.info('History is cleaned') 975 return 976 elif args[0] == '.': 977 output_file = os.path.join(self._export_dir, 'Cards', \ 978 'proc_card_mg5.dat') 979 output_file = open(output_file, 'w') 980 else: 981 output_file = open(args[0], 'w') 982 983 # Create the command file 984 text = self.get_history_header() 985 text += ('\n'.join(self.history) + '\n') 986 987 #write this information in a file 988 output_file.write(text) 989 output_file.close() 990 991 if self.log: 992 logger.info("History written to " + output_file.name)
993
994 - def compile(self, *args, **opts):
995 """ """ 996 997 return misc.compile(nb_core=self.options['nb_core'], *args, **opts)
998
999 - def avoid_history_duplicate(self, line, no_break=[]):
1000 """remove all line in history (but the last) starting with line. 1001 up to the point when a line didn't start by something in no_break. 1002 (reading in reverse order)""" 1003 1004 new_history = [] 1005 for i in range(1, len(self.history)+1): 1006 cur_line = self.history[-i] 1007 if i == 1: 1008 new_history.append(cur_line) 1009 elif not any((cur_line.startswith(text) for text in no_break)): 1010 to_add = self.history[:-i+1] 1011 to_add.reverse() 1012 new_history += to_add 1013 break 1014 elif cur_line.startswith(line): 1015 continue 1016 else: 1017 new_history.append(cur_line) 1018 1019 new_history.reverse() 1020 self.history[:] = new_history
1021 1022
1023 - def import_command_file(self, filepath):
1024 # remove this call from history 1025 if self.history: 1026 self.history.pop() 1027 1028 #avoid that command of other file interfere with this one. 1029 previous_store_line = self.get_stored_line() 1030 1031 # Read the lines of the file and execute them 1032 if isinstance(filepath, str): 1033 commandline = open(filepath).readlines() 1034 else: 1035 commandline = filepath 1036 oldinputfile = self.inputfile 1037 oldraw = self.use_rawinput 1038 self.inputfile = (l for l in commandline) # make a generator 1039 self.use_rawinput = False 1040 # Note using "for line in open(filepath)" is not safe since the file 1041 # filepath can be overwritten during the run (leading to weird results) 1042 # Note also that we need a generator and not a list. 1043 for line in self.inputfile: 1044 #remove pointless spaces and \n 1045 line = line.replace('\n', '').strip() 1046 # execute the line 1047 if line: 1048 self.exec_cmd(line, precmd=True) 1049 stored = self.get_stored_line() 1050 while stored: 1051 line = stored 1052 self.exec_cmd(line, precmd=True) 1053 stored = self.get_stored_line() 1054 1055 # If a child was open close it 1056 if self.child: 1057 self.child.exec_cmd('quit') 1058 self.inputfile = oldinputfile 1059 self.use_rawinput = oldraw 1060 1061 # restore original store line 1062 cmd = self 1063 while hasattr(cmd, 'mother') and cmd.mother: 1064 cmd = cmd.mother 1065 cmd.stored_line = previous_store_line 1066 return
1067
1068 - def get_history_header(self):
1069 """Default history header""" 1070 1071 return self.history_header
1072
1073 - def postloop(self):
1074 """ """ 1075 1076 args = self.split_arg(self.lastcmd) 1077 if args and args[0] in ['quit','exit']: 1078 if 'all' in args: 1079 return True 1080 if len(args) >1 and args[1].isdigit(): 1081 if args[1] not in ['0', '1']: 1082 return True 1083 return False
1084 1085 #=============================================================================== 1086 # Ask a question with a maximum amount of time to answer 1087 #=============================================================================== 1088 @staticmethod
1089 - def timed_input(question, default, timeout=None, noerror=True, fct=None, 1090 fct_timeout=None):
1091 """ a question with a maximal time to answer take default otherwise""" 1092 1093 def handle_alarm(signum, frame): 1094 raise TimeOutError
1095 1096 signal.signal(signal.SIGALRM, handle_alarm) 1097 1098 if fct is None: 1099 fct = raw_input 1100 1101 if timeout: 1102 signal.alarm(timeout) 1103 question += '[%ss to answer] ' % (timeout) 1104 try: 1105 result = fct(question) 1106 except TimeOutError: 1107 if noerror: 1108 logger.info('\nuse %s' % default) 1109 if fct_timeout: 1110 fct_timeout(True) 1111 return default 1112 else: 1113 signal.alarm(0) 1114 raise 1115 finally: 1116 signal.alarm(0) 1117 if fct_timeout: 1118 fct_timeout(False) 1119 return result
1120 1121 1122 1123 1124 1125 1126 # Quit
1127 - def do_quit(self, line):
1128 """Not in help: exit the mainloop() """ 1129 1130 if self.child: 1131 self.child.exec_cmd('quit ' + line, printcmd=False) 1132 return 1133 elif self.mother: 1134 self.mother.child = None 1135 if line == 'all': 1136 pass 1137 elif line: 1138 level = int(line) - 1 1139 if level: 1140 self.mother.lastcmd = 'quit %s' % level 1141 logger.info(' ') 1142 return True
1143 1144 # Aliases 1145 do_EOF = do_quit 1146 do_exit = do_quit 1147
1148 - def do_help(self, line):
1149 """Not in help: propose some usefull possible action """ 1150 1151 # if they are an argument use the default help 1152 if line: 1153 return cmd.Cmd.do_help(self, line) 1154 1155 1156 names = self.get_names() 1157 cmds = {} 1158 names.sort() 1159 # There can be duplicates if routines overridden 1160 prevname = '' 1161 for name in names: 1162 if name[:3] == 'do_': 1163 if name == prevname: 1164 continue 1165 prevname = name 1166 cmdname=name[3:] 1167 try: 1168 doc = getattr(self.cmd, name).__doc__ 1169 except Exception: 1170 doc = None 1171 if not doc: 1172 doc = getattr(self, name).__doc__ 1173 if not doc: 1174 tag = "Documented commands" 1175 elif ':' in doc: 1176 tag = doc.split(':',1)[0] 1177 else: 1178 tag = "Documented commands" 1179 if tag in cmds: 1180 cmds[tag].append(cmdname) 1181 else: 1182 cmds[tag] = [cmdname] 1183 1184 self.stdout.write("%s\n"%str(self.doc_leader)) 1185 for tag in self.helporder: 1186 if tag not in cmds: 1187 continue 1188 header = "%s (type help <topic>):" % tag 1189 self.print_topics(header, cmds[tag], 15,80) 1190 for name, item in cmds.items(): 1191 if name in self.helporder: 1192 continue 1193 if name == "Not in help": 1194 continue 1195 header = "%s (type help <topic>):" % name 1196 self.print_topics(header, item, 15,80) 1197 1198 1199 ## Add contextual help 1200 if len(self.history) == 0: 1201 last_action_2 = last_action = 'start' 1202 else: 1203 last_action_2 = last_action = 'none' 1204 1205 pos = 0 1206 authorize = self.next_possibility.keys() 1207 while last_action_2 not in authorize and last_action not in authorize: 1208 pos += 1 1209 if pos > len(self.history): 1210 last_action_2 = last_action = 'start' 1211 break 1212 1213 args = self.history[-1 * pos].split() 1214 last_action = args[0] 1215 if len(args)>1: 1216 last_action_2 = '%s %s' % (last_action, args[1]) 1217 else: 1218 last_action_2 = 'none' 1219 1220 logger.info('Contextual Help') 1221 logger.info('===============') 1222 if last_action_2 in authorize: 1223 options = self.next_possibility[last_action_2] 1224 elif last_action in authorize: 1225 options = self.next_possibility[last_action] 1226 else: 1227 return 1228 text = 'The following command(s) may be useful in order to continue.\n' 1229 for option in options: 1230 text+='\t %s \n' % option 1231 logger.info(text)
1232
1233 - def do_display(self, line, output=sys.stdout):
1234 """Advanced commands: basic display""" 1235 1236 args = self.split_arg(line) 1237 #check the validity of the arguments 1238 1239 if len(args) == 0: 1240 self.help_display() 1241 raise self.InvalidCmd, 'display require at least one argument' 1242 1243 if args[0] == "options": 1244 outstr = "Value of current Options:\n" 1245 for key, value in self.options.items(): 1246 outstr += '%25s \t:\t%s\n' %(key,value) 1247 output.write(outstr) 1248 1249 elif args[0] == "variable": 1250 outstr = "Value of Internal Variable:\n" 1251 try: 1252 var = eval(args[1]) 1253 except Exception: 1254 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1] 1255 else: 1256 outstr += 'GLOBAL:\n' 1257 outstr += misc.nice_representation(var, nb_space=4) 1258 1259 try: 1260 var = eval('self.%s' % args[1]) 1261 except Exception: 1262 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1] 1263 else: 1264 outstr += 'LOCAL:\n' 1265 outstr += misc.nice_representation(var, nb_space=4) 1266 split = args[1].split('.') 1267 for i, name in enumerate(split): 1268 try: 1269 __import__('.'.join(split[:i+1])) 1270 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1]))) 1271 except ImportError: 1272 try: 1273 var = eval(args[1]) 1274 except Exception, error: 1275 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1] 1276 break 1277 else: 1278 outstr += 'EXTERNAL:\n' 1279 outstr += misc.nice_representation(var, nb_space=4) 1280 else: 1281 var = eval(args[1]) 1282 outstr += 'EXTERNAL:\n' 1283 outstr += misc.nice_representation(var, nb_space=4) 1284 1285 pydoc.pager(outstr)
1286 1287
1288 - def do_save(self, line, check=True):
1289 """Save the configuration file""" 1290 1291 args = self.split_arg(line) 1292 # Check argument validity 1293 if check: 1294 Cmd.check_save(self, args) 1295 1296 # find base file for the configuration 1297 if'HOME' in os.environ and os.environ['HOME'] and \ 1298 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')): 1299 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt') 1300 if hasattr(self, 'me_dir'): 1301 basedir = self.me_dir 1302 elif not MADEVENT: 1303 basedir = MG5DIR 1304 else: 1305 basedir = os.getcwd() 1306 elif MADEVENT: 1307 # launch via ./bin/madevent 1308 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']: 1309 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)): 1310 base = pjoin(self.me_dir, 'Cards', config_file) 1311 basedir = self.me_dir 1312 else: 1313 if hasattr(self, 'me_dir'): 1314 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 1315 if len(args) == 0 and os.path.exists(base): 1316 self.write_configuration(base, base, self.me_dir) 1317 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 1318 basedir = MG5DIR 1319 1320 if len(args) == 0: 1321 args.append(base) 1322 self.write_configuration(args[0], base, basedir, self.options)
1323
1324 - def write_configuration(self, filepath, basefile, basedir, to_keep):
1325 """Write the configuration file""" 1326 # We use the default configuration file as a template. 1327 # to ensure that all configuration information are written we 1328 # keep track of all key that we need to write. 1329 1330 logger.info('save configuration file to %s' % filepath) 1331 to_write = to_keep.keys() 1332 text = "" 1333 # Use local configuration => Need to update the path 1334 for line in file(basefile): 1335 if '=' in line: 1336 data, value = line.split('=',1) 1337 else: 1338 text += line 1339 continue 1340 data = data.strip() 1341 if data.startswith('#'): 1342 key = data[1:].strip() 1343 else: 1344 key = data 1345 if '#' in value: 1346 value, comment = value.split('#',1) 1347 else: 1348 comment = '' 1349 if key in to_keep: 1350 value = str(to_keep[key]) 1351 else: 1352 text += line 1353 continue 1354 try: 1355 to_write.remove(key) 1356 except Exception: 1357 pass 1358 if '_path' in key: 1359 # special case need to update path 1360 # check if absolute path 1361 if not os.path.isabs(value): 1362 value = os.path.realpath(os.path.join(basedir, value)) 1363 text += '%s = %s # %s \n' % (key, value, comment) 1364 for key in to_write: 1365 if key in to_keep: 1366 text += '%s = %s \n' % (key, to_keep[key]) 1367 1368 if not MADEVENT: 1369 text += """\n# MG5 MAIN DIRECTORY\n""" 1370 text += "mg5_path = %s\n" % MG5DIR 1371 1372 writer = open(filepath,'w') 1373 writer.write(text) 1374 writer.close()
1375
1376 1377 1378 1379 -class CmdShell(Cmd):
1380 """CMD command with shell activate""" 1381 1382 # Access to shell
1383 - def do_shell(self, line):
1384 "Run a shell command" 1385 1386 if line.strip() is '': 1387 self.help_shell() 1388 else: 1389 logging.info("running shell command: " + line) 1390 subprocess.call(line, shell=True)
1391
1392 - def complete_shell(self, text, line, begidx, endidx):
1393 """ add path for shell """ 1394 1395 # Filename if directory is given 1396 # 1397 if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep: 1398 if not text: 1399 text = '' 1400 output = self.path_completion(text, 1401 base_dir=\ 1402 self.split_arg(line[0:begidx])[-1]) 1403 else: 1404 output = self.path_completion(text) 1405 return output
1406
1407 - def help_shell(self):
1408 """help for the shell""" 1409 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE') 1410 logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
1411
1412 1413 1414 1415 #=============================================================================== 1416 # Question with auto-completion 1417 #=============================================================================== 1418 -class SmartQuestion(BasicCmd):
1419 """ a class for answering a question with the path autocompletion""" 1420
1421 - def preloop(self):
1422 """Initializing before starting the main loop""" 1423 self.prompt = '>' 1424 self.value = None 1425 BasicCmd.preloop(self)
1426 1427
1428 - def __init__(self, question, allow_arg=[], default=None, 1429 mother_interface=None, *arg, **opt):
1430 self.question = question 1431 self.wrong_answer = 0 # forbids infinite loop 1432 self.allow_arg = [str(a) for a in allow_arg] 1433 self.history_header = '' 1434 self.default_value = str(default) 1435 self.mother_interface = mother_interface 1436 cmd.Cmd.__init__(self, *arg, **opt)
1437
1438 - def __call__(self, question, reprint_opt=True, **opts):
1439 1440 self.question = question 1441 for key,value in opts: 1442 setattr(self, key, value) 1443 if reprint_opt: 1444 print question 1445 return self.cmdloop()
1446 1447
1448 - def completenames(self, text, line, *ignored):
1449 prev_timer = signal.alarm(0) # avoid timer if any 1450 if prev_timer: 1451 nb_back = len(line) 1452 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1453 self.stdout.write(line) 1454 self.stdout.flush() 1455 try: 1456 out = {} 1457 out[' Options'] = Cmd.list_completion(text, self.allow_arg) 1458 out[' Recognized command'] = BasicCmd.completenames(self, text) 1459 1460 return self.deal_multiple_categories(out) 1461 except Exception, error: 1462 print error
1463
1464 - def get_names(self):
1465 # This method used to pull in base class attributes 1466 # at a time dir() didn't do it yet. 1467 return dir(self)
1468
1469 - def onecmd(self, line, **opt):
1470 """catch all error and stop properly command accordingly 1471 Interpret the argument as though it had been typed in response 1472 to the prompt. 1473 1474 The return value is a flag indicating whether interpretation of 1475 commands by the interpreter should stop. 1476 1477 This allow to pass extra argument for internal call. 1478 """ 1479 try: 1480 if '~/' in line and os.environ.has_key('HOME'): 1481 line = line.replace('~/', '%s/' % os.environ['HOME']) 1482 line = os.path.expandvars(line) 1483 cmd, arg, line = self.parseline(line) 1484 if not line: 1485 return self.emptyline() 1486 if cmd is None: 1487 return self.default(line) 1488 self.lastcmd = line 1489 if cmd == '': 1490 return self.default(line) 1491 else: 1492 try: 1493 func = getattr(self, 'do_' + cmd) 1494 except AttributeError: 1495 return self.default(line) 1496 return func(arg, **opt) 1497 except Exception as error: 1498 logger.warning(error)
1499
1500 - def reask(self, reprint_opt=True):
1501 pat = re.compile('\[(\d*)s to answer\]') 1502 prev_timer = signal.alarm(0) # avoid timer if any 1503 1504 if prev_timer: 1505 if pat.search(self.question): 1506 timeout = int(pat.search(self.question).groups()[0]) 1507 else: 1508 timeout=20 1509 print 1510 signal.alarm(timeout) 1511 if reprint_opt: 1512 if not prev_timer: 1513 self.question = pat.sub('',self.question) 1514 print self.question 1515 return False
1516
1517 - def default(self, line):
1518 """Default action if line is not recognized""" 1519 1520 if line.strip() == '' and self.default_value is not None: 1521 self.value = self.default_value 1522 else: 1523 self.value = line
1524
1525 - def emptyline(self):
1526 """If empty line, return default""" 1527 1528 if self.default_value is not None: 1529 self.value = self.default_value
1530 1531
1532 - def postcmd(self, stop, line):
1533 1534 try: 1535 if self.value in self.allow_arg: 1536 return True 1537 elif str(self.value) == 'EOF': 1538 self.value = self.default_value 1539 return True 1540 elif line and hasattr(self, 'do_%s' % line.split()[0]): 1541 return self.reask() 1542 elif self.value == 'repeat': 1543 return self.reask() 1544 elif len(self.allow_arg)==0: 1545 return True 1546 else: 1547 raise Exception 1548 except Exception,error: 1549 if self.wrong_answer < 100: 1550 self.wrong_answer += 1 1551 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \ 1552 % (self.value,','.join(self.allow_arg))) 1553 logger.warning('please retry') 1554 return False 1555 else: 1556 self.value = self.default_value 1557 return True
1558
1559 - def cmdloop(self, intro=None):
1560 cmd.Cmd.cmdloop(self, intro) 1561 return self.value
1562
1563 # a function helper 1564 -def smart_input(input_text, allow_arg=[], default=None):
1565 print input_text 1566 obj = SmartQuestion(allow_arg=allow_arg, default=default) 1567 return obj.cmdloop()
1568
1569 #=============================================================================== 1570 # Question in order to return a path with auto-completion 1571 #=============================================================================== 1572 -class OneLinePathCompletion(SmartQuestion):
1573 """ a class for answering a question with the path autocompletion""" 1574 1575 completion_prefix='' 1576
1577 - def completenames(self, text, line, begidx, endidx):
1578 prev_timer = signal.alarm(0) # avoid timer if any 1579 if prev_timer: 1580 nb_back = len(line) 1581 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1582 self.stdout.write(line) 1583 self.stdout.flush() 1584 1585 try: 1586 out = {} 1587 out[' Options'] = Cmd.list_completion(text, self.allow_arg) 1588 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False) 1589 out[' Recognized command'] = BasicCmd.completenames(self, text) 1590 1591 return self.deal_multiple_categories(out) 1592 except Exception, error: 1593 print error
1594
1595 - def precmd(self, *args):
1596 """ """ 1597 1598 signal.alarm(0) 1599 return SmartQuestion.precmd(self, *args)
1600
1601 - def completedefault(self,text, line, begidx, endidx):
1602 prev_timer = signal.alarm(0) # avoid timer if any 1603 if prev_timer: 1604 nb_back = len(line) 1605 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1606 self.stdout.write(line) 1607 self.stdout.flush() 1608 try: 1609 args = Cmd.split_arg(line[0:begidx]) 1610 except Exception, error: 1611 print error 1612 1613 # Directory continuation 1614 if args[-1].endswith(os.path.sep): 1615 1616 return Cmd.path_completion(text, 1617 os.path.join('.',*[a for a in args \ 1618 if a.endswith(os.path.sep)])) 1619 self.completenames(line+text)
1620 1621
1622 - def postcmd(self, stop, line):
1623 try: 1624 if self.value in self.allow_arg: 1625 return True 1626 elif self.value and os.path.isfile(self.value): 1627 return os.path.relpath(self.value) 1628 elif self.value and str(self.value) == 'EOF': 1629 self.value = self.default_value 1630 return True 1631 elif line and hasattr(self, 'do_%s' % line.split()[0]): 1632 # go to retry 1633 reprint_opt = True 1634 elif self.value == 'repeat': 1635 reprint_opt = True 1636 else: 1637 raise Exception 1638 except Exception, error: 1639 print """not valid argument. Valid argument are file path or value in (%s).""" \ 1640 % ','.join(self.allow_arg) 1641 print 'please retry' 1642 reprint_opt = False 1643 1644 return self.reask(reprint_opt)
1645
1646 1647 # a function helper 1648 -def raw_path_input(input_text, allow_arg=[], default=None):
1649 print input_text 1650 obj = OneLinePathCompletion(allow_arg=allow_arg, default=default ) 1651 return obj.cmdloop()
1652
1653 #=============================================================================== 1654 # 1655 #=============================================================================== 1656 -class CmdFile(file):
1657 """ a class for command input file -in order to debug cmd \n problem""" 1658
1659 - def __init__(self, name, opt='rU'):
1660 1661 file.__init__(self, name, opt) 1662 self.text = file.read(self) 1663 self.close() 1664 self.lines = self.text.split('\n')
1665
1666 - def readline(self, *arg, **opt):
1667 """readline method treating correctly a line whithout \n at the end 1668 (add it) 1669 """ 1670 if self.lines: 1671 line = self.lines.pop(0) 1672 else: 1673 return '' 1674 1675 if line.endswith('\n'): 1676 return line 1677 else: 1678 return line + '\n'
1679
1680 - def __next__(self):
1681 return self.lines.__next__()
1682
1683 - def __iter__(self):
1684 return self.lines.__iter__()
1685