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