1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """ A file containing different extension of the cmd basic python library"""
16
17
18 import logging
19 import math
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')
36 logger_stderr = logging.getLogger('fatalerror')
37
38 try:
39 import madgraph.various.misc as misc
40 from madgraph import MG5DIR, MadGraph5Error
41 MADEVENT = False
42 except ImportError, error:
43 try:
44 import internal.misc as misc
45 except:
46 raise error
47
48 MADEVENT = True
49
50
51 pjoin = os.path.join
54 """Class for run-time error"""
55
56 -def debug(debug_only=True):
57
58 def deco_debug(f):
59
60 if debug_only and not __debug__:
61 return f
62
63 def deco_f(*args, **opt):
64 try:
65 return f(*args, **opt)
66 except Exception, error:
67 logger.error(error)
68 logger.error(traceback.print_exc(file=sys.stdout))
69 return
70 return deco_f
71 return deco_debug
72
73 import string
74
75
76 __all__ = ["Cmd"]
77 PROMPT = '(Cmd) '
78 IDENTCHARS = string.ascii_letters + string.digits + '_'
80 """A simple framework for writing line-oriented command interpreters.
81
82 These are often useful for test harnesses, administrative tools, and
83 prototypes that will later be wrapped in a more sophisticated interface.
84
85 A Cmd instance or subclass instance is a line-oriented interpreter
86 framework. There is no good reason to instantiate Cmd itself; rather,
87 it's useful as a superclass of an interpreter class you define yourself
88 in order to inherit Cmd's methods and encapsulate action methods.
89
90 """
91 prompt = PROMPT
92 identchars = IDENTCHARS
93 ruler = '='
94 lastcmd = ''
95 intro = None
96 doc_leader = ""
97 doc_header = "Documented commands (type help <topic>):"
98 misc_header = "Miscellaneous help topics:"
99 undoc_header = "Undocumented commands:"
100 nohelp = "*** No help on %s"
101 use_rawinput = 1
102
103 - def __init__(self, completekey='tab', stdin=None, stdout=None,**opt):
104 """Instantiate a line-oriented interpreter framework.
105
106 The optional argument 'completekey' is the readline name of a
107 completion key; it defaults to the Tab key. If completekey is
108 not None and the readline module is available, command completion
109 is done automatically. The optional arguments stdin and stdout
110 specify alternate input and output file objects; if not specified,
111 sys.stdin and sys.stdout are used.
112
113 """
114 import sys
115 if stdin is not None:
116 self.stdin = stdin
117 else:
118 self.stdin = sys.stdin
119 if stdout is not None:
120 self.stdout = stdout
121 else:
122 self.stdout = sys.stdout
123 self.cmdqueue = []
124 self.completekey = completekey
125 self.cmd_options = opt
126
128 """Repeatedly issue a prompt, accept input, parse an initial prefix
129 off the received input, and dispatch to action methods, passing them
130 the remainder of the line as argument.
131
132 """
133
134 self.preloop()
135 if self.use_rawinput and self.completekey:
136 try:
137 import readline
138 self.old_completer = readline.get_completer()
139 readline.set_completer(self.complete)
140 readline.parse_and_bind(self.completekey+": complete")
141 except ImportError:
142 pass
143 try:
144 if intro is not None:
145 self.intro = intro
146 if self.intro:
147 self.stdout.write(str(self.intro)+"\n")
148 stop = None
149 while not stop:
150 if self.cmdqueue:
151 line = self.cmdqueue.pop(0)
152 else:
153 if self.use_rawinput:
154 try:
155 line = raw_input(self.prompt)
156 except EOFError:
157 line = 'EOF'
158 else:
159 self.stdout.write(self.prompt)
160 self.stdout.flush()
161 line = self.stdin.readline()
162 if not len(line):
163 line = 'EOF'
164 else:
165 line = line.rstrip('\r\n')
166 line = self.precmd(line)
167 stop = self.onecmd(line)
168 stop = self.postcmd(stop, line)
169 self.postloop()
170 finally:
171 if self.use_rawinput and self.completekey:
172 try:
173 import readline
174 readline.set_completer(self.old_completer)
175 except ImportError:
176 pass
177
178
180 """Hook method executed just before the command line is
181 interpreted, but after the input prompt is generated and issued.
182
183 """
184 return line
185
186 - def postcmd(self, stop, line):
187 """Hook method executed just after a command dispatch is finished."""
188 return stop
189
191 """Hook method executed once when the cmdloop() method is called."""
192 pass
193
194 - def postloop(self):
195 """Hook method executed once when the cmdloop() method is about to
196 return.
197
198 """
199 pass
200
202 """Parse the line into a command name and a string containing
203 the arguments. Returns a tuple containing (command, args, line).
204 'command' and 'args' may be None if the line couldn't be parsed.
205 """
206 line = line.strip()
207 if not line:
208 return None, None, line
209 elif line[0] == '?':
210 line = 'help ' + line[1:]
211 elif line[0] == '!':
212 if hasattr(self, 'do_shell'):
213 line = 'shell ' + line[1:]
214 else:
215 return None, None, line
216 i, n = 0, len(line)
217 while i < n and line[i] in self.identchars: i = i+1
218 cmd, arg = line[:i], line[i:].strip()
219 return cmd, arg, line
220
222 """Interpret the argument as though it had been typed in response
223 to the prompt.
224
225 This may be overridden, but should not normally need to be;
226 see the precmd() and postcmd() methods for useful execution hooks.
227 The return value is a flag indicating whether interpretation of
228 commands by the interpreter should stop.
229
230 """
231 cmd, arg, line = self.parseline(line)
232 if not line:
233 return self.emptyline()
234 if cmd is None:
235 return self.default(line)
236 self.lastcmd = line
237 if cmd == '':
238 return self.default(line)
239 else:
240 try:
241 func = getattr(self, 'do_' + cmd)
242 except AttributeError:
243 return self.default(line)
244 return func(arg)
245
247 """Called when an empty line is entered in response to the prompt.
248
249 If this method is not overridden, it repeats the last nonempty
250 command entered.
251
252 """
253 if self.lastcmd:
254 return self.onecmd(self.lastcmd)
255
257 """Called on an input line when the command prefix is not recognized.
258
259 If this method is not overridden, it prints an error message and
260 returns.
261
262 """
263 self.stdout.write('*** Unknown syntax: %s\n'%line)
264
266 """Method called to complete an input line when no command-specific
267 complete_*() method is available.
268
269 By default, it returns an empty list.
270
271 """
272 return []
273
275 dotext = 'do_'+text
276
277 done = set()
278
279 return [a[3:] for a in self.get_names()
280 if a.startswith(dotext) and a not in done and not done.add(a)]
281
283 """Return the next possible completion for 'text'.
284
285 If a command has not been entered, then complete against command list.
286 Otherwise try to call complete_<command> to get list of completions.
287 """
288 if state == 0:
289 import readline
290 origline = readline.get_line_buffer()
291 line = origline.lstrip()
292 stripped = len(origline) - len(line)
293 begidx = readline.get_begidx() - stripped
294 endidx = readline.get_endidx() - stripped
295 if begidx>0:
296 cmd, args, foo = self.parseline(line)
297 if cmd == '':
298 compfunc = self.completedefault
299 else:
300 try:
301 compfunc = getattr(self, 'complete_' + cmd)
302 except AttributeError:
303 compfunc = self.completedefault
304 else:
305 compfunc = self.completenames
306 self.completion_matches = compfunc(text, line, begidx, endidx)
307 try:
308 return self.completion_matches[state]
309 except IndexError:
310 return None
311
313
314
315 names = []
316 classes = [self.__class__]
317 while classes:
318 aclass = classes.pop(0)
319 if aclass.__bases__:
320 classes = classes + list(aclass.__bases__)
321 names = names + dir(aclass)
322 return names
323
326
328 if arg:
329
330 try:
331 func = getattr(self, 'help_' + arg)
332 except AttributeError:
333 try:
334 doc=getattr(self, 'do_' + arg).__doc__
335 if doc:
336 self.stdout.write("%s\n"%str(doc))
337 return
338 except AttributeError:
339 pass
340 self.stdout.write("%s\n"%str(self.nohelp % (arg,)))
341 return
342 func()
343 else:
344 names = self.get_names()
345 cmds_doc = []
346 cmds_undoc = []
347 help = {}
348 for name in names:
349 if name[:5] == 'help_':
350 help[name[5:]]=1
351 names.sort()
352
353 prevname = ''
354 for name in names:
355 if name[:3] == 'do_':
356 if name == prevname:
357 continue
358 prevname = name
359 cmd=name[3:]
360 if cmd in help:
361 cmds_doc.append(cmd)
362 del help[cmd]
363 elif getattr(self, name).__doc__:
364 cmds_doc.append(cmd)
365 else:
366 cmds_undoc.append(cmd)
367 self.stdout.write("%s\n"%str(self.doc_leader))
368 self.print_topics(self.doc_header, cmds_doc, 15,80)
369 self.print_topics(self.misc_header, help.keys(),15,80)
370 self.print_topics(self.undoc_header, cmds_undoc, 15,80)
371
379
381 """Display a list of strings as a compact set of columns.
382
383 Each column is only as wide as necessary.
384 Columns are separated by two spaces (one was not legible enough).
385 """
386 if not list:
387 self.stdout.write("<empty>\n")
388 return
389 nonstrings = [i for i in range(len(list))
390 if not isinstance(list[i], str)]
391 if nonstrings:
392 raise TypeError, ("list[i] not a string for i in %s" %
393 ", ".join(map(str, nonstrings)))
394 size = len(list)
395 if size == 1:
396 self.stdout.write('%s\n'%str(list[0]))
397 return
398
399 for nrows in range(1, len(list)):
400 ncols = (size+nrows-1) // nrows
401 colwidths = []
402 totwidth = -2
403 for col in range(ncols):
404 colwidth = 0
405 for row in range(nrows):
406 i = row + nrows*col
407 if i >= size:
408 break
409 x = list[i]
410 colwidth = max(colwidth, len(x))
411 colwidths.append(colwidth)
412 totwidth += colwidth + 2
413 if totwidth > displaywidth:
414 break
415 if totwidth <= displaywidth:
416 break
417 else:
418 nrows = len(list)
419 ncols = 1
420 colwidths = [0]
421 for row in range(nrows):
422 texts = []
423 for col in range(ncols):
424 i = row + nrows*col
425 if i >= size:
426 x = ""
427 else:
428 x = list[i]
429 texts.append(x)
430 while texts and not texts[-1]:
431 del texts[-1]
432 for col in range(len(texts)):
433 texts[col] = texts[col].ljust(colwidths[col])
434 self.stdout.write("%s\n"%str(" ".join(texts)))
435
436
437
438
439
440
441
442 -class BasicCmd(OriginalCmd):
443 """Simple extension for the readline"""
444
446 """ This has been refactorized here so that it can be called when another
447 program called by MG5 (such as MadAnalysis5) changes this attribute of readline"""
448 if readline:
449 if not 'libedit' in readline.__doc__:
450 readline.set_completion_display_matches_hook(self.print_suggestions)
451 else:
452 readline.set_completion_display_matches_hook()
453
457
459 """convert the multiple category in a formatted list understand by our
460 specific readline parser"""
461
462 if not formatting:
463 return dico
464
465 if 'libedit' in readline.__doc__:
466
467 out = []
468 for name, opt in dico.items():
469 out += opt
470 return out
471
472
473 if not forceCategory and all(len(s) <= 1 for s in dico.values() ):
474 values = set((s[0] for s in dico.values() if len(s)==1))
475 if len(values) == 1:
476 return values
477
478
479 out = []
480 valid=0
481
482 for name, opt in dico.items():
483 if not opt:
484 continue
485 name = name.replace(' ', '_')
486 valid += 1
487 out.append(opt[0].rstrip()+'@@'+name+'@@')
488
489 d = {}
490 for x in opt:
491 d[x] = 1
492 opt = list(d.keys())
493 opt.sort()
494 out += opt
495
496 if not forceCategory and valid == 1:
497 out = out[1:]
498
499 return out
500
501 @debug()
503 """print auto-completions by category"""
504 if not hasattr(self, 'completion_prefix'):
505 self.completion_prefix = ''
506 longest_match_length += len(self.completion_prefix)
507 try:
508 if len(matches) == 1:
509 self.stdout.write(matches[0]+' ')
510 return
511 self.stdout.write('\n')
512 l2 = [a[-2:] for a in matches]
513 if '@@' in l2:
514 nb_column = self.getTerminalSize()//(longest_match_length+1)
515 pos=0
516 for val in self.completion_matches:
517 if val.endswith('@@'):
518 category = val.rsplit('@@',2)[1]
519 category = category.replace('_',' ')
520 self.stdout.write('\n %s:\n%s\n' % (category, '=' * (len(category)+2)))
521 start = 0
522 pos = 0
523 continue
524 elif pos and pos % nb_column ==0:
525 self.stdout.write('\n')
526 self.stdout.write(self.completion_prefix + val + \
527 ' ' * (longest_match_length +1 -len(val)))
528 pos +=1
529 self.stdout.write('\n')
530 else:
531
532 nb_column = self.getTerminalSize()//(longest_match_length+1)
533 for i,val in enumerate(matches):
534 if i and i%nb_column ==0:
535 self.stdout.write('\n')
536 self.stdout.write(self.completion_prefix + val + \
537 ' ' * (longest_match_length +1 -len(val)))
538 self.stdout.write('\n')
539
540 self.stdout.write(self.prompt+readline.get_line_buffer())
541 self.stdout.flush()
542 except Exception, error:
543 if __debug__:
544 logger.error(error)
545
547 def ioctl_GWINSZ(fd):
548 try:
549 import fcntl, termios, struct
550 cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
551 '1234'))
552 except Exception:
553 return None
554 return cr
555 cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
556 if not cr:
557 try:
558 fd = os.open(os.ctermid(), os.O_RDONLY)
559 cr = ioctl_GWINSZ(fd)
560 os.close(fd)
561 except Exception:
562 pass
563 if not cr:
564 try:
565 cr = (os.environ['LINES'], os.environ['COLUMNS'])
566 except Exception:
567 cr = (25, 80)
568 return int(cr[1])
569
571 """Return the next possible completion for 'text'.
572 If a command has not been entered, then complete against command list.
573 Otherwise try to call complete_<command> to get list of completions.
574 """
575 if state == 0:
576 import readline
577 origline = readline.get_line_buffer()
578 line = origline.lstrip()
579 stripped = len(origline) - len(line)
580 begidx = readline.get_begidx() - stripped
581 endidx = readline.get_endidx() - stripped
582
583 if ';' in line:
584 begin, line = line.rsplit(';',1)
585 begidx = begidx - len(begin) - 1
586 endidx = endidx - len(begin) - 1
587 if line[:begidx] == ' ' * begidx:
588 begidx=0
589
590 if begidx>0:
591 cmd, args, foo = self.parseline(line)
592 if cmd == '':
593 compfunc = self.completedefault
594 else:
595 try:
596 compfunc = getattr(self, 'complete_' + cmd)
597 except AttributeError, error:
598 compfunc = self.completedefault
599 except Exception, error:
600 misc.sprint(error)
601 else:
602 compfunc = self.completenames
603
604
605 if line and begidx > 2 and line[begidx-2:begidx] == '\ ':
606 Ntext = line.split(os.path.sep)[-1]
607 self.completion_prefix = Ntext.rsplit('\ ', 1)[0] + '\ '
608 to_rm = len(self.completion_prefix) - 1
609 Nbegidx = len(line.rsplit(os.path.sep, 1)[0]) + 1
610 data = compfunc(Ntext.replace('\ ', ' '), line, Nbegidx, endidx)
611 self.completion_matches = [p[to_rm:] for p in data
612 if len(p)>to_rm]
613
614 elif line and line[begidx-1] in ['-',"=",':']:
615 try:
616 sep = line[begidx-1]
617 Ntext = line.split()[-1]
618 self.completion_prefix = Ntext.rsplit(sep,1)[0] + sep
619 to_rm = len(self.completion_prefix)
620 Nbegidx = len(line.rsplit(None, 1)[0])
621 data = compfunc(Ntext, line, Nbegidx, endidx)
622 self.completion_matches = [p[to_rm:] for p in data
623 if len(p)>to_rm]
624 except Exception, error:
625 print error
626 else:
627 self.completion_prefix = ''
628 self.completion_matches = compfunc(text, line, begidx, endidx)
629
630 self.completion_matches = [ l if l[-1] in [' ','@','=',os.path.sep]
631 else ((l + ' ') if not l.endswith('\\$') else l[:-2])
632 for l in self.completion_matches if l]
633
634 try:
635 return self.completion_matches[state]
636 except IndexError, error:
637
638
639
640 return None
641
642 @staticmethod
644 """Split a line of arguments"""
645
646 split = line.split()
647 out=[]
648 tmp=''
649 for data in split:
650 if data[-1] == '\\':
651 tmp += data[:-1]+' '
652 elif tmp:
653 tmp += data
654 tmp = os.path.expanduser(os.path.expandvars(tmp))
655 out.append(tmp)
656
657
658 tmp = ''
659 else:
660 out.append(data)
661 return out
662
663 @staticmethod
665 """Propose completions of text in list"""
666
667 if not text:
668 completions = list
669 else:
670 completions = [ f
671 for f in list
672 if f.startswith(text)
673 ]
674
675 return completions
676
677
678 @staticmethod
679 - def path_completion(text, base_dir = None, only_dirs = False,
680 relative=True):
681 """Propose completions of text to compose a valid path"""
682
683 if base_dir is None:
684 base_dir = os.getcwd()
685 base_dir = os.path.expanduser(os.path.expandvars(base_dir))
686
687 if text == '~':
688 text = '~/'
689 prefix, text = os.path.split(text)
690 prefix = os.path.expanduser(os.path.expandvars(prefix))
691 base_dir = os.path.join(base_dir, prefix)
692 if prefix:
693 prefix += os.path.sep
694
695 if only_dirs:
696 completion = [prefix + f + os.path.sep
697 for f in os.listdir(base_dir)
698 if f.startswith(text) and \
699 os.path.isdir(os.path.join(base_dir, f)) and \
700 (not f.startswith('.') or text.startswith('.'))
701 ]
702 else:
703 completion = [ prefix + f
704 for f in os.listdir(base_dir)
705 if f.startswith(text) and \
706 os.path.isfile(os.path.join(base_dir, f)) and \
707 (not f.startswith('.') or text.startswith('.'))
708 ]
709
710 completion = completion + \
711 [prefix + f + os.path.sep
712 for f in os.listdir(base_dir)
713 if f.startswith(text) and \
714 os.path.isdir(os.path.join(base_dir, f)) and \
715 (not f.startswith('.') or text.startswith('.'))
716 ]
717
718 if relative:
719 completion += [prefix + f for f in ['.'+os.path.sep, '..'+os.path.sep] if \
720 f.startswith(text) and not prefix.startswith('.')]
721
722 completion = [a.replace(' ','\ ') for a in completion]
723 return completion
724
729 """Extension of the cmd object for only the check command"""
730
731 - def check_history(self, args):
732 """check the validity of line"""
733
734 if len(args) > 1:
735 self.help_history()
736 raise self.InvalidCmd('\"history\" command takes at most one argument')
737
738 if not len(args):
739 return
740
741 if args[0] =='.':
742 if not self._export_dir:
743 raise self.InvalidCmd("No default directory is defined for \'.\' option")
744 elif args[0] != 'clean':
745 dirpath = os.path.dirname(args[0])
746 if dirpath and not os.path.exists(dirpath) or \
747 os.path.isdir(args[0]):
748 raise self.InvalidCmd("invalid path %s " % dirpath)
749
751 """check that the line is compatible with save options"""
752
753 if len(args) > 2:
754 self.help_save()
755 raise self.InvalidCmd, 'too many arguments for save command.'
756
757 if len(args) == 2:
758 if args[0] != 'options':
759 self.help_save()
760 raise self.InvalidCmd, '\'%s\' is not recognized as first argument.' % \
761 args[0]
762 else:
763 args.pop(0)
764
766 """Extension of the cmd object for only the help command"""
767
769 logger.info("-- terminates the application",'$MG:color:BLUE')
770 logger.info("syntax: quit",'$MG:color:BLACK')
771
772 help_EOF = help_quit
773
774 - def help_history(self):
775 logger.info("-- interact with the command history.",'$MG:color:BLUE')
776 logger.info("syntax: history [FILEPATH|clean|.] ",'$MG:color:BLACK')
777 logger.info(" > If FILEPATH is \'.\' and \'output\' is done,")
778 logger.info(" Cards/proc_card_mg5.dat will be used.")
779 logger.info(" > If FILEPATH is omitted, the history will be output to stdout.")
780 logger.info(" \"clean\" will remove all entries from the history.")
781
783 logger.info("-- access to the in-line help",'$MG:color:BLUE')
784 logger.info("syntax: help",'$MG:color:BLACK')
785
787 """help text for save"""
788 logger.info("-- save options configuration to filepath.",'$MG:color:BLUE')
789 logger.info("syntax: save [options] [FILEPATH]",'$MG:color:BLACK')
790
792 """help for display command"""
793 logger.info("-- display a the status of various internal state variables",'$MG:color:BLUE')
794 logger.info("syntax: display " + "|".join(self._display_opts),'$MG:color:BLACK')
795
804
805 - def complete_history(self, text, line, begidx, endidx):
806 "Complete the history command"
807
808 args = self.split_arg(line[0:begidx])
809
810
811 if args[-1].endswith(os.path.sep):
812 return self.path_completion(text,
813 os.path.join('.',*[a for a in args \
814 if a.endswith(os.path.sep)]))
815
816 if len(args) == 1:
817 return self.path_completion(text)
818
820 "Complete the save command"
821
822 args = self.split_arg(line[0:begidx])
823
824
825 if len(args) == 1:
826 return self.list_completion(text, ['options'])
827
828
829 if args[-1].endswith(os.path.sep):
830 return self.path_completion(text,
831 pjoin('.',*[a for a in args if a.endswith(os.path.sep)]),
832 only_dirs = True)
833
834
835 if len(args) == 2:
836 return self.path_completion(text)
837
838 -class Cmd(CheckCmd, HelpCmd, CompleteCmd, BasicCmd):
839 """Extension of the cmd.Cmd command line.
840 This extensions supports line breaking, history, comments,
841 internal call to cmdline, path completion,...
842 this class should be MG5 independent"""
843
844
845 next_possibility = {}
846 history_header = ""
847
848 _display_opts = ['options','variable']
849 allow_notification_center = True
850
852 """expected error for wrong command"""
853 pass
854
855 ConfigurationError = InvalidCmd
856
857 debug_output = 'debug'
858 error_debug = """Please report this bug to developers\n
859 More information is found in '%(debug)s'.\n
860 Please attach this file to your report."""
861 config_debug = error_debug
862
863 keyboard_stop_msg = """stopping all current operation
864 in order to quit the program please enter exit"""
865
866 if MADEVENT:
867 plugin_path = []
868 else:
869 plugin_path = [pjoin(MG5DIR, 'PLUGIN')]
870 if 'PYTHONPATH' in os.environ:
871 for PluginCandidate in os.environ['PYTHONPATH'].split(':'):
872 try:
873 dirlist = os.listdir(PluginCandidate)
874 except OSError:
875 continue
876 for onedir in dirlist:
877 if onedir == 'MG5aMC_PLUGIN':
878 plugin_path.append(pjoin(PluginCandidate, 'MG5aMC_PLUGIN'))
879 break
880 else:
881 continue
882 break
883
885 """Init history and line continuation"""
886
887 self.log = True
888 self.history = []
889 self.save_line = ''
890 super(Cmd, self).__init__(*arg, **opt)
891 self.__initpos = os.path.abspath(os.getcwd())
892 self.child = None
893 self.mother = None
894 self.inputfile = None
895 self.haspiping = not sys.stdin.isatty()
896 self.stored_line = ''
897
898 if not hasattr(self, 'helporder'):
899 self.helporder = ['Documented commands']
900
902 """Hook method executed once when the cmdloop() method is called."""
903 if self.completekey:
904 try:
905 import readline
906 self.old_completer = readline.get_completer()
907 readline.set_completer(self.complete)
908 readline.parse_and_bind(self.completekey+": complete")
909 except ImportError:
910 readline = None
911 pass
912 if readline and not 'libedit' in readline.__doc__:
913 readline.set_completion_display_matches_hook(self.print_suggestions)
914
915
917
918 self.preloop()
919 if intro is not None:
920 self.intro = intro
921 if self.intro:
922 print self.intro
923 stop = None
924 while not stop:
925 if self.cmdqueue:
926 line = self.cmdqueue[0]
927 del self.cmdqueue[0]
928 else:
929 if self.use_rawinput:
930 try:
931 line = raw_input(self.prompt)
932 except EOFError:
933 line = 'EOF'
934 else:
935 sys.stdout.write(self.prompt)
936 sys.stdout.flush()
937 line = sys.stdin.readline()
938 if not len(line):
939 line = 'EOF'
940 else:
941 line = line[:-1]
942 try:
943 line = self.precmd(line)
944 stop = self.onecmd(line)
945 except BaseException, error:
946 self.error_handling(error, line)
947 if isinstance(error, KeyboardInterrupt):
948 stop = True
949 finally:
950 stop = self.postcmd(stop, line)
951 self.postloop()
952
954 """avoid to have html opening / notification"""
955 self.allow_notification_center = False
956 try:
957 self.options['automatic_html_opening'] = False
958 self.options['notification_center'] = False
959
960 except:
961 pass
962
963
965 """ A suite of additional function needed for in the cmd
966 this implement history, line breaking, comment treatment,...
967 """
968
969 if not line:
970 return line
971
972
973 if self.save_line:
974 line = self.save_line + line
975 self.save_line = ''
976
977 line = line.lstrip()
978
979 if line.endswith('\\'):
980 self.save_line = line[:-1]
981 return ''
982
983
984 if '#' in line:
985 line = line.split('#')[0]
986
987
988 if ';' in line:
989 lines = line.split(';')
990 for subline in lines:
991 if not (subline.startswith("history") or subline.startswith('help') \
992 or subline.startswith('#*')):
993 self.history.append(subline)
994 stop = self.onecmd_orig(subline)
995 stop = self.postcmd(stop, subline)
996 return ''
997
998
999 self.history.append(line)
1000 return line
1001
1002 - def postcmd(self,stop, line):
1003 """ finishing a command
1004 This looks if the command add a special post part."""
1005
1006 if line.strip():
1007 try:
1008 cmd, subline = line.split(None, 1)
1009 except ValueError:
1010 pass
1011 else:
1012 if hasattr(self,'post_%s' %cmd):
1013 stop = getattr(self, 'post_%s' % cmd)(stop, subline)
1014 return stop
1015
1039
1040
1041
1042
1043 - def ask(self, question, default, choices=[], path_msg=None,
1044 timeout = True, fct_timeout=None, ask_class=None, alias={},
1045 first_cmd=None, text_format='4', force=False,
1046 return_instance=False, **opt):
1047 """ ask a question with some pre-define possibility
1048 path info is
1049 """
1050
1051 if path_msg:
1052 path_msg = [path_msg]
1053 else:
1054 path_msg = []
1055
1056 if timeout is True:
1057 try:
1058 timeout = self.options['timeout']
1059 except Exception:
1060 pass
1061
1062
1063 if choices + path_msg:
1064 question += ' ['
1065 question += "\033[%sm%s\033[0m, " % (text_format, default)
1066 for data in choices[:9] + path_msg:
1067 if default == data:
1068 continue
1069 else:
1070 question += "%s, " % data
1071
1072 if len(choices) > 9:
1073 question += '... , '
1074 question = question[:-2]+']'
1075 else:
1076 question += "[\033[%sm%s\033[0m] " % (text_format, default)
1077 if ask_class:
1078 obj = ask_class
1079 elif path_msg:
1080 obj = OneLinePathCompletion
1081 else:
1082 obj = SmartQuestion
1083
1084 if alias:
1085 choices += alias.keys()
1086
1087 question_instance = obj(question, allow_arg=choices, default=default,
1088 mother_interface=self, **opt)
1089
1090 if first_cmd:
1091 if isinstance(first_cmd, str):
1092 question_instance.onecmd(first_cmd)
1093 else:
1094 for line in first_cmd:
1095 question_instance.onecmd(line)
1096 if not self.haspiping:
1097 if hasattr(obj, "haspiping"):
1098 obj.haspiping = self.haspiping
1099
1100 if force:
1101 answer = default
1102 else:
1103 answer = self.check_answer_in_input_file(question_instance, default, path_msg)
1104 if answer is not None:
1105 if answer in alias:
1106 answer = alias[answer]
1107 if ask_class:
1108 line=answer
1109 answer = question_instance.default(line)
1110 question_instance.postcmd(answer, line)
1111 if not return_instance:
1112 return question_instance.answer
1113 else:
1114 return question_instance.answer , question_instance
1115 if hasattr(question_instance, 'check_answer_consistency'):
1116 question_instance.check_answer_consistency()
1117 if not return_instance:
1118 return answer
1119 else:
1120 return answer, question_instance
1121
1122 question = question_instance.question
1123 if not force:
1124 value = Cmd.timed_input(question, default, timeout=timeout,
1125 fct=question_instance, fct_timeout=fct_timeout)
1126 else:
1127 value = default
1128
1129 try:
1130 if value in alias:
1131 value = alias[value]
1132 except TypeError:
1133 pass
1134
1135 if value == default and ask_class:
1136 value = question_instance.default(default)
1137
1138 if not return_instance:
1139 return value
1140 else:
1141 return value, question_instance
1142
1152
1153
1155 """check import command"""
1156
1157 if '-f' in args:
1158 self.force = True
1159 args.remove('-f')
1160 if args[0] != 'command':
1161 args.set(0, 'command')
1162 if len(args) != 2:
1163 raise self.InvalidCmd('import command requires one filepath argument')
1164 if not os.path.exists(args[1]):
1165 raise 'No such file or directory %s' % args[1]
1166
1167
1249
1251 """store a line of the input file which should be executed by the higher mother"""
1252
1253 if self.mother:
1254 self.mother.store_line(line)
1255 else:
1256 self.stored_line = line
1257
1259 """return stored line and clean it"""
1260 if self.mother:
1261 value = self.mother.get_stored_line()
1262 self.mother.stored_line = None
1263 else:
1264 value = self.stored_line
1265 self.stored_line = None
1266 return value
1267
1268
1269
1271 """ """
1272
1273 if self.child:
1274 return self.child.nice_error_handling(error, line)
1275
1276 os.chdir(self.__initpos)
1277
1278 self.log = False
1279 if os.path.exists(self.debug_output):
1280 os.remove(self.debug_output)
1281 try:
1282 super(Cmd,self).onecmd('history %s' % self.debug_output.replace(' ', '\ '))
1283 except Exception, error:
1284 logger.error(error)
1285
1286 debug_file = open(self.debug_output, 'a')
1287 traceback.print_exc(file=debug_file)
1288 if hasattr(error, 'filename'):
1289 debug_file.write("Related File: %s\n" % error.filename)
1290
1291 if self.history and line == self.history[-1]:
1292 error_text = 'Command \"%s\" interrupted with error:\n' % line
1293 elif self.history:
1294 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
1295 error_text += '\"%s\" with error:\n' % self.history[-1]
1296 else:
1297 error_text = ''
1298 error_text += '%s : %s\n' % (error.__class__.__name__,
1299 str(error).replace('\n','\n\t'))
1300 error_text += self.error_debug % {'debug':self.debug_output}
1301 logger_stderr.critical(error_text)
1302
1303
1304
1305 try:
1306 self.do_display('options', debug_file)
1307 except Exception, error:
1308 debug_file.write('Fail to write options with error %s' % error)
1309
1310
1311 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']:
1312 try:
1313 ff = open(pjoin(self.me_dir, 'Cards', card))
1314 debug_file.write(ff.read())
1315 ff.close()
1316 except Exception:
1317 pass
1318
1319
1320 if hasattr(self, 'options') and 'crash_on_error' in self.options and \
1321 self.options['crash_on_error']:
1322 logger.info('stop computation due to crash_on_error=True')
1323 sys.exit(str(error))
1324
1325 if self.use_rawinput == False:
1326 return True
1327 return False
1328
1329
1330
1332 if self.child:
1333 return self.child.nice_user_error(error, line)
1334
1335 os.chdir(self.__initpos)
1336 if not self.history or line == self.history[-1]:
1337 error_text = 'Command \"%s\" interrupted with error:\n' % line
1338 else:
1339 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
1340 error_text += '\"%s\" with error:\n' % self.history[-1]
1341 error_text += '%s : %s' % (error.__class__.__name__,
1342 str(error).replace('\n','\n\t'))
1343 logger_stderr.error(error_text)
1344
1345 if hasattr(self, 'options') and 'crash_on_error' in self.options and \
1346 self.options['crash_on_error']:
1347 logger.info('stop computation due to crash_on_error=True')
1348 sys.exit(str(error))
1349
1350 if self.use_rawinput == False:
1351 return True
1352
1353 self.history.pop()
1354 return False
1355
1357 if self.child:
1358 return self.child.nice_user_error(error, line)
1359
1360 os.chdir(self.__initpos)
1361 if not self.history or line == self.history[-1]:
1362 error_text = 'Error detected in \"%s\"\n' % line
1363 else:
1364 error_text = 'Error detected in sub-command %s\n' % self.history[-1]
1365 error_text += 'write debug file %s \n' % self.debug_output
1366 self.log = False
1367 super(Cmd,self).onecmd('history %s' % self.debug_output)
1368 debug_file = open(self.debug_output, 'a')
1369 traceback.print_exc(file=debug_file)
1370 error_text += self.config_debug % {'debug' :self.debug_output}
1371 error_text += '%s : %s' % (error.__class__.__name__,
1372 str(error).replace('\n','\n\t'))
1373 logger_stderr.error(error_text)
1374
1375
1376 try:
1377 self.do_display('options', debug_file)
1378 except Exception, error:
1379 debug_file.write('Fail to write options with error %s' % error)
1380 if hasattr(self, 'options') and 'crash_on_error' in self.options and \
1381 self.options['crash_on_error']:
1382 logger.info('stop computation due to crash_on_error=True')
1383 sys.exit(str(error))
1384
1385
1386 if self.use_rawinput == False:
1387 return True
1388
1389 if self.history:
1390 self.history.pop()
1391 return False
1392
1394 """Interpret the argument as though it had been typed in response
1395 to the prompt.
1396
1397 The return value is a flag indicating whether interpretation of
1398 commands by the interpreter should stop.
1399
1400 This allow to pass extra argument for internal call.
1401 """
1402 if '~/' in line and os.environ.has_key('HOME'):
1403 line = line.replace('~/', '%s/' % os.environ['HOME'])
1404 if '#' in line:
1405 line = line.split('#')[0]
1406
1407 line = os.path.expandvars(line)
1408 cmd, arg, line = self.parseline(line)
1409 if not line:
1410 return self.emptyline()
1411 if cmd is None:
1412 return self.default(line)
1413 self.lastcmd = line
1414 if cmd == '':
1415 return self.default(line)
1416 else:
1417 try:
1418 func = getattr(self, 'do_' + cmd)
1419 except AttributeError:
1420 return self.default(line)
1421 return func(arg, **opt)
1422
1460
1461
1462
1463 - def onecmd(self, line, **opt):
1464 """catch all error and stop properly command accordingly"""
1465
1466 try:
1467 return self.onecmd_orig(line, **opt)
1468 except BaseException, error:
1469 self.error_handling(error, line)
1470
1471
1473 """action to perform to close nicely on a keyboard interupt"""
1474 pass
1475
1476 - def exec_cmd(self, line, errorhandling=False, printcmd=True,
1477 precmd=False, postcmd=True,
1478 child=True, **opt):
1498
1500 """for third party call, call the line with pre and postfix treatment
1501 with global error handling"""
1502
1503 return self.exec_cmd(line, errorhandling=True, precmd=True)
1504
1506 """If empty line, do nothing. Default is repeat previous command."""
1507 pass
1508
1509 - def default(self, line, log=True):
1510 """Default action if line is not recognized"""
1511
1512
1513 if log:
1514 logger.warning("Command \"%s\" not recognized, please try again" % \
1515 line.split()[0])
1516 if line.strip() in ['q', '.q', 'stop']:
1517 logger.info("If you want to quit mg5 please type \"exit\".")
1518
1519 if self.history and self.history[-1] == line:
1520 self.history.pop()
1521
1522
1523 - def do_history(self, line):
1524 """write in a file the suite of command that was used"""
1525
1526 args = self.split_arg(line)
1527
1528 self.check_history(args)
1529
1530 if len(args) == 0:
1531 logger.info('\n'.join(self.history))
1532 return
1533 elif args[0] == 'clean':
1534 self.history = []
1535 logger.info('History is cleaned')
1536 return
1537 elif args[0] == '.':
1538 output_file = os.path.join(self._export_dir, 'Cards', \
1539 'proc_card_mg5.dat')
1540 output_file = open(output_file, 'w')
1541 else:
1542 output_file = open(args[0], 'w')
1543
1544
1545 text = self.get_history_header()
1546 text += ('\n'.join(self.history) + '\n')
1547
1548
1549 output_file.write(text)
1550 output_file.close()
1551
1552 if self.log:
1553 logger.info("History written to " + output_file.name)
1554
1555 - def compile(self, *args, **opts):
1559
1560 - def avoid_history_duplicate(self, line, no_break=[]):
1561 """remove all line in history (but the last) starting with line.
1562 up to the point when a line didn't start by something in no_break.
1563 (reading in reverse order)"""
1564
1565 new_history = []
1566 for i in range(1, len(self.history)+1):
1567 cur_line = self.history[-i]
1568 if i == 1:
1569 new_history.append(cur_line)
1570 elif not any((cur_line.startswith(text) for text in no_break)):
1571 to_add = self.history[:-i+1]
1572 to_add.reverse()
1573 new_history += to_add
1574 break
1575 elif cur_line.startswith(line):
1576 continue
1577 else:
1578 new_history.append(cur_line)
1579
1580 new_history.reverse()
1581 self.history[:] = new_history
1582
1583
1585
1586 if self.history:
1587 self.history.pop()
1588
1589
1590 previous_store_line = self.get_stored_line()
1591
1592
1593 if isinstance(filepath, str):
1594 commandline = open(filepath).readlines()
1595 else:
1596 commandline = filepath
1597 oldinputfile = self.inputfile
1598 oldraw = self.use_rawinput
1599 self.inputfile = (l for l in commandline)
1600 self.use_rawinput = False
1601
1602
1603
1604 for line in self.inputfile:
1605
1606 line = line.replace('\n', '').strip()
1607
1608 if line:
1609 self.exec_cmd(line, precmd=True)
1610 stored = self.get_stored_line()
1611 while stored:
1612 line = stored
1613 self.exec_cmd(line, precmd=True)
1614 stored = self.get_stored_line()
1615
1616
1617 if self.child:
1618 self.child.exec_cmd('quit')
1619 self.inputfile = oldinputfile
1620 self.use_rawinput = oldraw
1621
1622
1623 cmd = self
1624 while hasattr(cmd, 'mother') and cmd.mother:
1625 cmd = cmd.mother
1626 cmd.stored_line = previous_store_line
1627 return
1628
1630 """Default history header"""
1631
1632 return self.history_header
1633
1634 - def postloop(self):
1635 """ """
1636
1637 if self.use_rawinput and self.completekey:
1638 try:
1639 import readline
1640 readline.set_completer(self.old_completer)
1641 del self.old_completer
1642 except ImportError:
1643 pass
1644 except AttributeError:
1645 pass
1646
1647 args = self.split_arg(self.lastcmd)
1648 if args and args[0] in ['quit','exit']:
1649 if 'all' in args:
1650 return True
1651 if len(args) >1 and args[1].isdigit():
1652 if args[1] not in ['0', '1']:
1653 return True
1654
1655 return False
1656
1657
1658
1659
1660 @staticmethod
1667
1668 signal.signal(signal.SIGALRM, handle_alarm)
1669
1670 if fct is None:
1671 fct = raw_input
1672
1673 if timeout:
1674 signal.alarm(timeout)
1675 question += '[%ss to answer] ' % (timeout)
1676 try:
1677 result = fct(question)
1678 except TimeOutError:
1679 if noerror:
1680 logger.info('\nuse %s' % default)
1681 if fct_timeout:
1682 fct_timeout(True)
1683 return default
1684 else:
1685 signal.alarm(0)
1686 raise
1687 finally:
1688 signal.alarm(0)
1689 if fct_timeout:
1690 fct_timeout(False)
1691 return result
1692
1693
1694
1695
1696
1697
1698
1700 """Not in help: exit the mainloop() """
1701
1702 if self.child:
1703 self.child.exec_cmd('quit ' + line, printcmd=False)
1704 return
1705 elif self.mother:
1706 self.mother.child = None
1707 if line == 'all':
1708 pass
1709 elif line:
1710 level = int(line) - 1
1711 if level:
1712 self.mother.lastcmd = 'quit %s' % level
1713 logger.info(' ')
1714 return True
1715
1716
1717 do_EOF = do_quit
1718 do_exit = do_quit
1719
1721 """Not in help: propose some usefull possible action """
1722
1723
1724 if line:
1725 return super(Cmd, self).do_help(line)
1726
1727
1728 names = self.get_names()
1729 cmds = {}
1730 names.sort()
1731
1732 prevname = ''
1733 for name in names:
1734 if name[:3] == 'do_':
1735 if name == prevname:
1736 continue
1737 prevname = name
1738 cmdname=name[3:]
1739 try:
1740 doc = getattr(self.cmd, name).__doc__
1741 except Exception:
1742 doc = None
1743 if not doc:
1744 doc = getattr(self, name).__doc__
1745 if not doc:
1746 tag = "Documented commands"
1747 elif ':' in doc:
1748 tag = doc.split(':',1)[0]
1749 else:
1750 tag = "Documented commands"
1751 if tag in cmds:
1752 cmds[tag].append(cmdname)
1753 else:
1754 cmds[tag] = [cmdname]
1755
1756 self.stdout.write("%s\n"%str(self.doc_leader))
1757 for tag in self.helporder:
1758 if tag not in cmds:
1759 continue
1760 header = "%s (type help <topic>):" % tag
1761 self.print_topics(header, cmds[tag], 15,80)
1762 for name, item in cmds.items():
1763 if name in self.helporder:
1764 continue
1765 if name == "Not in help":
1766 continue
1767 header = "%s (type help <topic>):" % name
1768 self.print_topics(header, item, 15,80)
1769
1770
1771
1772 if len(self.history) == 0:
1773 last_action_2 = last_action = 'start'
1774 else:
1775 last_action_2 = last_action = 'none'
1776
1777 pos = 0
1778 authorize = self.next_possibility.keys()
1779 while last_action_2 not in authorize and last_action not in authorize:
1780 pos += 1
1781 if pos > len(self.history):
1782 last_action_2 = last_action = 'start'
1783 break
1784
1785 args = self.history[-1 * pos].split()
1786 last_action = args[0]
1787 if len(args)>1:
1788 last_action_2 = '%s %s' % (last_action, args[1])
1789 else:
1790 last_action_2 = 'none'
1791
1792 logger.info('Contextual Help')
1793 logger.info('===============')
1794 if last_action_2 in authorize:
1795 options = self.next_possibility[last_action_2]
1796 elif last_action in authorize:
1797 options = self.next_possibility[last_action]
1798 else:
1799 return
1800 text = 'The following command(s) may be useful in order to continue.\n'
1801 for option in options:
1802 text+='\t %s \n' % option
1803 logger.info(text)
1804
1806 """Advanced commands: basic display"""
1807
1808 args = self.split_arg(line)
1809
1810
1811 if len(args) == 0:
1812 self.help_display()
1813 raise self.InvalidCmd, 'display require at least one argument'
1814
1815 if args[0] == "options":
1816 outstr = "Value of current Options:\n"
1817 for key, value in self.options.items():
1818 outstr += '%25s \t:\t%s\n' %(key,value)
1819 output.write(outstr)
1820
1821 elif args[0] == "variable":
1822 outstr = "Value of Internal Variable:\n"
1823 try:
1824 var = eval(args[1])
1825 except Exception:
1826 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
1827 else:
1828 outstr += 'GLOBAL:\n'
1829 outstr += misc.nice_representation(var, nb_space=4)
1830
1831 try:
1832 var = eval('self.%s' % args[1])
1833 except Exception:
1834 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
1835 else:
1836 outstr += 'LOCAL:\n'
1837 outstr += misc.nice_representation(var, nb_space=4)
1838 split = args[1].split('.')
1839 for i, name in enumerate(split):
1840 try:
1841 __import__('.'.join(split[:i+1]))
1842 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1])))
1843 except ImportError:
1844 try:
1845 var = eval(args[1])
1846 except Exception, error:
1847 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1]
1848 break
1849 else:
1850 outstr += 'EXTERNAL:\n'
1851 outstr += misc.nice_representation(var, nb_space=4)
1852 else:
1853 var = eval(args[1])
1854 outstr += 'EXTERNAL:\n'
1855 outstr += misc.nice_representation(var, nb_space=4)
1856
1857 pydoc.pager(outstr)
1858
1859
1860 - def do_save(self, line, check=True):
1861 """Save the configuration file"""
1862
1863 args = self.split_arg(line)
1864
1865 if check:
1866 Cmd.check_save(self, args)
1867
1868
1869 if 'HOME' in os.environ and os.environ['HOME'] and \
1870 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
1871 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
1872 if hasattr(self, 'me_dir'):
1873 basedir = self.me_dir
1874 elif not MADEVENT:
1875 basedir = MG5DIR
1876 else:
1877 basedir = os.getcwd()
1878 elif MADEVENT:
1879
1880 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']:
1881 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)):
1882 base = pjoin(self.me_dir, 'Cards', config_file)
1883 basedir = self.me_dir
1884 else:
1885 if hasattr(self, 'me_dir'):
1886 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1887 if len(args) == 0 and os.path.exists(base):
1888 self.write_configuration(base, base, self.me_dir)
1889 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1890 basedir = MG5DIR
1891
1892 if len(args) == 0:
1893 args.append(base)
1894 self.write_configuration(args[0], base, basedir, self.options)
1895
1897 """Write the configuration file"""
1898
1899
1900
1901
1902 logger.info('save configuration file to %s' % filepath)
1903 to_write = to_keep.keys()
1904 text = ""
1905 has_mg5_path = False
1906
1907 for line in file(basefile):
1908 if '=' in line:
1909 data, value = line.split('=',1)
1910 else:
1911 text += line
1912 continue
1913 data = data.strip()
1914 if data.startswith('#'):
1915 key = data[1:].strip()
1916 else:
1917 key = data
1918 if '#' in value:
1919 value, comment = value.split('#',1)
1920 else:
1921 comment = ''
1922 if key in to_keep:
1923 value = str(to_keep[key])
1924 else:
1925 text += line
1926 continue
1927 if key == 'mg5_path':
1928 has_mg5_path = True
1929 try:
1930 to_write.remove(key)
1931 except Exception:
1932 pass
1933 if '_path' in key:
1934
1935
1936 if not os.path.isabs(value):
1937 value = os.path.realpath(os.path.join(basedir, value))
1938 text += '%s = %s # %s \n' % (key, value, comment)
1939 for key in to_write:
1940 if key in to_keep:
1941 text += '%s = %s \n' % (key, to_keep[key])
1942
1943 if not MADEVENT and not has_mg5_path:
1944 text += """\n# MG5 MAIN DIRECTORY\n"""
1945 text += "mg5_path = %s\n" % MG5DIR
1946
1947 writer = open(filepath,'w')
1948 writer.write(text)
1949 writer.close()
1950
1955 """CMD command with shell activate"""
1956
1957
1959 "Run a shell command"
1960
1961 if line.strip() is '':
1962 self.help_shell()
1963 else:
1964 logging.info("running shell command: " + line)
1965 subprocess.call(line, shell=True)
1966
1968 """ add path for shell """
1969
1970
1971
1972 if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep:
1973 if not text:
1974 text = ''
1975 output = self.path_completion(text,
1976 base_dir=\
1977 self.split_arg(line[0:begidx])[-1])
1978 else:
1979 output = self.path_completion(text)
1980 return output
1981
1983 """help for the shell"""
1984 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')
1985 logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
1986
1994 """ a class for answering a question with the path autocompletion"""
1995
1996 allowpath = False
1998 """Initializing before starting the main loop"""
1999 self.prompt = '>'
2000 self.value = None
2001 BasicCmd.preloop(self)
2002
2003 @property
2006
2007 - def __init__(self, question, allow_arg=[], default=None,
2008 mother_interface=None, *arg, **opt):
2009 self.question = question
2010 self.wrong_answer = 0
2011 self.allow_arg = [str(a) for a in allow_arg]
2012 self.history_header = ''
2013 self.default_value = str(default)
2014 self.mother_interface = mother_interface
2015
2016 if 'case' in opt:
2017 self.casesensitive = opt['case']
2018 del opt['case']
2019 elif 'casesensitive' in opt:
2020 self.casesensitive = opt['casesensitive']
2021 del opt['casesensitive']
2022 else:
2023 self.casesensistive = True
2024 super(SmartQuestion, self).__init__(*arg, **opt)
2025
2026 - def __call__(self, question, reprint_opt=True, **opts):
2027
2028 self.question = question
2029 for key,value in opts:
2030 setattr(self, key, value)
2031 if reprint_opt:
2032 print question
2033 return self.cmdloop()
2034
2035
2037 prev_timer = signal.alarm(0)
2038 if prev_timer:
2039 nb_back = len(line)
2040 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2041 self.stdout.write(line)
2042 self.stdout.flush()
2043 try:
2044 out = {}
2045 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2046 out[' Recognized command'] = super(SmartQuestion, self).completenames(text,line, *ignored)
2047
2048 return self.deal_multiple_categories(out)
2049 except Exception, error:
2050 print error
2051
2052 completedefault = completenames
2053
2055
2056
2057 return dir(self)
2058
2059 - def onecmd(self, line, **opt):
2060 """catch all error and stop properly command accordingly
2061 Interpret the argument as though it had been typed in response
2062 to the prompt.
2063
2064 The return value is a flag indicating whether interpretation of
2065 commands by the interpreter should stop.
2066
2067 This allow to pass extra argument for internal call.
2068 """
2069 try:
2070 if '~/' in line and os.environ.has_key('HOME'):
2071 line = line.replace('~/', '%s/' % os.environ['HOME'])
2072 line = os.path.expandvars(line)
2073 cmd, arg, line = self.parseline(line)
2074 if not line:
2075 return self.emptyline()
2076 if cmd is None:
2077 return self.default(line)
2078 self.lastcmd = line
2079 if cmd == '':
2080 return self.default(line)
2081 else:
2082 try:
2083 func = getattr(self, 'do_' + cmd)
2084 except AttributeError:
2085 return self.default(line)
2086 return func(arg, **opt)
2087 except Exception as error:
2088 logger.warning(error)
2089 if __debug__:
2090 raise
2091
2092 - def reask(self, reprint_opt=True):
2093 pat = re.compile('\[(\d*)s to answer\]')
2094 prev_timer = signal.alarm(0)
2095
2096 if prev_timer:
2097 if pat.search(self.question):
2098 timeout = int(pat.search(self.question).groups()[0])
2099 signal.alarm(timeout)
2100 if reprint_opt:
2101 if not prev_timer:
2102 self.question = pat.sub('',self.question)
2103 print self.question
2104
2105 if self.mother_interface:
2106 answer = self.mother_interface.check_answer_in_input_file(self, 'EOF',
2107 path=self.allowpath)
2108 if answer:
2109 stop = self.default(answer)
2110 self.postcmd(stop, answer)
2111 return False
2112
2113 return False
2114
2116
2117 text=line
2118 out ={}
2119 out['Options'] = Cmd.list_completion(text, self.allow_arg)
2120 out['command'] = BasicCmd.completenames(self, text)
2121
2122 if not text:
2123 if out['Options']:
2124 logger.info( "Here is the list of all valid options:", '$MG:color:BLACK')
2125 logger.info( " "+ "\n ".join(out['Options']))
2126 if out['command']:
2127 logger.info( "Here is the list of command available:", '$MG:color:BLACK')
2128 logger.info( " "+ "\n ".join(out['command']))
2129 else:
2130 if out['Options']:
2131 logger.info( "Here is the list of all valid options starting with \'%s\'" % text, '$MG:color:BLACK')
2132 logger.info( " "+ "\n ".join(out['Options']))
2133 if out['command']:
2134 logger.info( "Here is the list of command available starting with \'%s\':" % text, '$MG:color:BLACK')
2135 logger.info( " "+ "\n ".join(out['command']))
2136 elif not out['Options']:
2137 logger.info( "No possibility starting with \'%s\'" % text, '$MG:color:BLACK')
2138 logger.info( "You can type help XXX, to see all command starting with XXX", '$MG:color:BLACK')
2142
2144 """Default action if line is not recognized"""
2145
2146 if line.strip() == '' and self.default_value is not None:
2147 self.value = self.default_value
2148 else:
2149 self.value = line
2150
2152 """If empty line, return default"""
2153
2154 if self.default_value is not None:
2155 self.value = self.default_value
2156
2157
2158 - def postcmd(self, stop, line):
2159
2160 try:
2161 if self.value in self.allow_arg:
2162 return True
2163 elif str(self.value) == 'EOF':
2164 self.value = self.default_value
2165 return True
2166 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2167 return self.reask()
2168 elif self.value in ['repeat', 'reask']:
2169 return self.reask()
2170 elif len(self.allow_arg)==0:
2171 return True
2172 elif ' ' in line.strip() and '=' in self.value:
2173 line,n = re.subn(r'\s*=\s*', '=', line)
2174 if n:
2175 self.default(line)
2176 return self.postcmd(stop, line)
2177 if not self.casesensitive:
2178 for ans in self.allow_arg:
2179 if ans.lower() == self.value.lower():
2180 self.value = ans
2181 return True
2182 break
2183 else:
2184 raise Exception
2185
2186
2187 else:
2188 raise Exception
2189 except Exception,error:
2190 if self.wrong_answer < 100:
2191 self.wrong_answer += 1
2192 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
2193 % (self.value,','.join(self.allow_arg)))
2194 logger.warning('please retry')
2195 return False
2196 else:
2197 self.value = self.default_value
2198 return True
2199
2203
2209
2214 """ a class for answering a question with the path autocompletion"""
2215
2216 completion_prefix=''
2217 allowpath=True
2218
2219 - def completenames(self, text, line, begidx, endidx, formatting=True):
2220 prev_timer = signal.alarm(0)
2221 if prev_timer:
2222 nb_back = len(line)
2223 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2224 self.stdout.write(line)
2225 self.stdout.flush()
2226
2227 try:
2228 out = {}
2229 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2230 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
2231 out[' Recognized command'] = BasicCmd.completenames(self, text, line, begidx, endidx)
2232
2233 return self.deal_multiple_categories(out, formatting)
2234 except Exception, error:
2235 print error
2236
2242
2244 prev_timer = signal.alarm(0)
2245 if prev_timer:
2246 nb_back = len(line)
2247 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2248 self.stdout.write(line)
2249 self.stdout.flush()
2250 try:
2251 args = Cmd.split_arg(line[0:begidx])
2252 except Exception, error:
2253 print error
2254
2255
2256 if args[-1].endswith(os.path.sep):
2257
2258 return Cmd.path_completion(text,
2259 os.path.join('.',*[a for a in args \
2260 if a.endswith(os.path.sep)]),
2261 begidx, endidx)
2262 return self.completenames(text, line, begidx, endidx)
2263
2264
2265 - def postcmd(self, stop, line):
2266 try:
2267 if self.value in self.allow_arg:
2268 return True
2269 elif self.value and os.path.isfile(self.value):
2270 return os.path.relpath(self.value)
2271 elif self.value and str(self.value) == 'EOF':
2272 self.value = self.default_value
2273 return True
2274 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2275
2276 reprint_opt = True
2277 elif self.value == 'repeat':
2278 reprint_opt = True
2279 else:
2280 raise Exception
2281 except Exception, error:
2282 print """not valid argument. Valid argument are file path or value in (%s).""" \
2283 % ','.join(self.allow_arg)
2284 print 'please retry'
2285 reprint_opt = False
2286
2287 if line != 'EOF':
2288 return self.reask(reprint_opt)
2289
2296
2300 """A class for asking a question on which program to run.
2301 This is the abstract class
2302
2303 Behavior for each switch can be customize via:
2304 set_default_XXXX() -> set default value
2305 get_allowed_XXXX() -> return list of possible value
2306 check_value_XXXX(value) -> return True/False if the user can set such value
2307 switch_off_XXXXX() -> set it off (called for special mode)
2308 color_for_XXXX(value) -> return the representation on the screen for value
2309 get_cardcmd_for_XXXX(value)> return the command to run to customize the cards to
2310 match the status
2311
2312 consistency_XX_YY(val_XX, val_YY)
2313 -> XX is the new key set by the user to a new value val_XX
2314 -> YY is another key set by the user.
2315 -> return value should be None or "replace_YY"
2316
2317 consistency_XX(val_XX):
2318 check the consistency of the other switch given the new status of this one.
2319 return a dict {key:replaced_value} or {} if nothing to do
2320
2321 user typing "NAME" will result to a call to self.ans_NAME(None)
2322 user typing "NAME=XX" will result to a call to self.ans_NAME('XX')
2323
2324 Note on case sensitivity:
2325 -------------------------
2326 the XXX is displayed with the case in self.to_control
2327 but ALL functions should use the lower case version.
2328 for key associated to get_allowed_keys(),
2329 if (user) value not in that list.
2330 -> try to find the first entry matching up to the case
2331 for ans_XXX, set the value to lower case, but if case_XXX is set to True
2332 """
2333
2334 case_sensitive = False
2335 quit_on = ['0','done', 'EOF','','auto']
2336
2337 - def __init__(self, to_control, motherinstance, *args, **opts):
2338 """to_control is a list of ('KEY': 'Choose the shower/hadronization program')
2339 """
2340
2341 self.to_control = to_control
2342 self.mother_interface = motherinstance
2343 self.inconsistent_keys = {}
2344
2345
2346 self.inconsistent_details = {}
2347 self.last_changed = []
2348
2349
2350 self.switch = {}
2351 for key, _ in to_control:
2352 self.switch[key.lower()] = 'temporary'
2353
2354 self.set_default_switch()
2355 question = self.create_question()
2356
2357
2358 allowed_args = [ `i`+';' for i in range(1, 1+len(self.to_control))]
2359 for key in self.switch:
2360 allowed_args += ['%s=%s;' % (key,s) for s in self.get_allowed(key)]
2361
2362 allowed_args += [key[4:]+';' for key in dir(self) if key.startswith('ans_')]
2363 if 'allow_arg' in opts:
2364 allowed_args += opts['allow_arg']
2365 del opts['allow_arg']
2366
2367 super(ControlSwitch, self).__init__(question, allowed_args, *args, **opts)
2368 self.options = self.mother_interface.options
2369
2396
2397
2398
2399
2400
2409
2411 """use this if they are no dedicated function for such key"""
2412
2413 if hasattr(self, 'get_allowed_%s' % key):
2414 return getattr(self, 'get_allowed_%s' % key)()[0]
2415 else:
2416 self.switch[key] = 'OFF'
2417
2419 """set all valid parameter to OFF --call before special keyword--
2420 """
2421
2422 for key in self.switch:
2423 if hasattr(self, 'switch_off_%s' % key):
2424 getattr(self, 'switch_off_%s' % key)()
2425 elif self.check_value(key, self.switch[key]):
2426 self.switch[key] = 'OFF'
2427 self.inconsistent_details = {}
2428 self.inconsistent_keys = {}
2429
2430
2432 """return True/False if the value is a correct value to be set by the USER.
2433 other value than those can be set by the system --like-- Not available.
2434 This does not check the full consistency of the switch
2435 """
2436
2437 if hasattr(self, 'check_value_%s' % key):
2438 return getattr(self, 'check_value_%s' % key)(value)
2439 elif value in self.get_allowed(key):
2440 return True
2441 else:
2442 return False
2443
2444
2446 """ return the list of command that need to be run to have a consistent
2447 set of cards with the switch value choosen """
2448
2449 switch = self.answer
2450 cmd= []
2451 for key in self.switch:
2452 if hasattr(self, 'get_cardcmd_for_%s' % key):
2453 cmd += getattr(self, 'get_cardcmd_for_%s' % key)(switch[key])
2454 return cmd
2455
2456
2458 """return the list of possible value for key"""
2459
2460 if hasattr(self, 'get_allowed_%s' % key):
2461 return getattr(self, 'get_allowed_%s' % key)()
2462 else:
2463 return ['ON', 'OFF']
2464
2466 """Default action if line is not recognized"""
2467
2468 line=line.strip().replace('@', '__at__')
2469 if ';' in line:
2470 for l in line.split(';'):
2471 if l:
2472 out = self.default(l)
2473 return out
2474
2475 if '=' in line:
2476 base, value = line.split('=',1)
2477
2478 if base.isdigit() :
2479 try:
2480 base = self.to_control[int(base)-1][0]
2481 except:
2482 pass
2483 elif ' ' in line:
2484 base, value = line.split(' ', 1)
2485 elif hasattr(self, 'ans_%s' % line.lower()):
2486 base, value = line.lower(), None
2487 elif line.isdigit() and line in [`i` for i in range(1, len(self.switch)+1)]:
2488
2489 base = self.to_control[int(line)-1][0].lower()
2490 return self.default(base)
2491 elif line.lower() in self.switch:
2492
2493 base = line.lower()
2494 try:
2495 cur = self.get_allowed(base).index(self.switch[base])
2496 except:
2497 if self.get_allowed(base):
2498 value = self.get_allowed(base)[0]
2499 else:
2500 logger.warning('Can not switch "%s" to another value via number', base)
2501 self.value='reask'
2502 return
2503 else:
2504 try:
2505 value = self.get_allowed(base)[cur+1]
2506 except IndexError:
2507 value = self.get_allowed(base)[0]
2508 elif line in ['', 'done', 'EOF', 'eof','0']:
2509 super(ControlSwitch, self).default(line)
2510 return self.answer
2511 elif line in 'auto':
2512 self.switch['dynamical'] = True
2513 return super(ControlSwitch, self).default(line)
2514 else:
2515 logger.warning('unknow command: %s' % line)
2516 self.value = 'reask'
2517 return
2518
2519 self.value = 'reask'
2520 base = base.lower()
2521 if hasattr(self, 'ans_%s' % base):
2522 if value and not self.is_case_sensitive(base):
2523 value = value.lower()
2524 getattr(self, 'ans_%s' % base)(value)
2525 elif base in self.switch:
2526 self.set_switch(base, value)
2527 else:
2528 logger.warning('Not valid command: %s' % line)
2529
2531 """check if a key is case sensitive"""
2532
2533 case = self.case_sensitive
2534 if hasattr(self, 'case_%s' % key):
2535 case = getattr(self, 'case_%s' % key)
2536 return case
2537
2538 - def onecmd(self, line, **opt):
2543
2544 @property
2546
2547
2548 for key,_ in self.to_control:
2549 if not self.check_value(key, self.switch[key]):
2550 self.switch[key] = 'OFF'
2551
2552 if not self.inconsistent_keys:
2553 return self.switch
2554 else:
2555 out = dict(self.switch)
2556 out.update(self.inconsistent_keys)
2557 return out
2558
2559 - def postcmd(self, stop, line):
2560
2561 line = line.strip()
2562 if ';' in line:
2563 line= [l for l in line.split(';') if l][-1]
2564 if line in self.quit_on:
2565 return True
2566 self.create_question()
2567 return self.reask(True)
2568
2569
2571 """change a switch to a given value"""
2572
2573 assert key in self.switch
2574
2575
2576
2577 if hasattr(self, 'ans_%s' % key):
2578 if not self.is_case_sensitive(key):
2579 value = value.lower()
2580 return getattr(self, 'ans_%s' % key)(value)
2581
2582 if not self.is_case_sensitive(key) and value not in self.get_allowed(key):
2583 lower = [t.lower() for t in self.get_allowed(key)]
2584 try:
2585 ind = lower.index(value.lower())
2586 except ValueError:
2587 pass
2588 else:
2589 value = self.get_allowed(key)[ind]
2590
2591 check = self.check_value(key, value)
2592 if not check:
2593 logger.warning('"%s" not valid option for "%s"', value, key)
2594 return
2595 if isinstance(check, str):
2596 value = check
2597
2598 self.switch[key] = value
2599
2600 if user:
2601 self.check_consistency(key, value)
2602
2604
2605 if not keys:
2606 self.inconsistent_keys = {}
2607 self.inconsistent_details = {}
2608 elif isinstance(keys, list):
2609 for key in keys:
2610 if key in self.inconsistent_keys:
2611 del self.inconsistent_keys[keys]
2612 del self.inconsistent_details[keys]
2613 else:
2614 if keys in self.inconsistent_keys:
2615 del self.inconsistent_keys[keys]
2616 del self.inconsistent_details[keys]
2617
2619 """check the consistency of the new flag with the old ones"""
2620
2621 if key in self.last_changed:
2622 self.last_changed.remove(key)
2623 self.last_changed.append(key)
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637 if hasattr(self, 'consistency_%s' % key):
2638 rules = dict([(key2, None) for key2 in self.switch])
2639 rules.update(getattr(self, 'consistency_%s' % key)(value, self.switch))
2640 else:
2641 rules = {}
2642 for key2,value2 in self.switch.items():
2643 if hasattr(self, 'consistency_%s_%s' % (key,key2)):
2644 rules[key2] = getattr(self, 'consistency_%s_%s' % (key,key2))(value, value2)
2645
2646
2647 if rules[key2] is not None and not self.check_value(key2, rules[key2]):
2648 if rules[key2] != 'OFF':
2649 logger.debug('consistency_%s_%s returns invalid output. Assume no conflict')
2650 rules[key2] = None
2651 else:
2652 rules[key2] = None
2653
2654
2655
2656
2657
2658 self.remove_inconsistency(key)
2659
2660 for key2 in self.switch:
2661 if rules[key2]:
2662 info = {'orig_value': self.switch[key2],
2663 'changed_key': key,
2664 'new_changed_key_val': value,
2665 'replacement': rules[key2]}
2666 if key2 in self.inconsistent_details:
2667 self.inconsistent_details[key2].append(info)
2668 else:
2669 self.inconsistent_details[key2] = [info]
2670
2671 if not self.inconsistent_details:
2672 return
2673
2674
2675 for key2 in dict(self.inconsistent_details):
2676 for conflict in list(self.inconsistent_details[key2]):
2677 keep_conflict = True
2678
2679 if conflict['orig_value'] != self.switch[key2]:
2680 keep_conflict = False
2681
2682 if self.switch[conflict['changed_key']] != conflict['new_changed_key_val']:
2683 keep_conflict = False
2684 if not keep_conflict:
2685 self.inconsistent_details[key2].remove(conflict)
2686 if not self.inconsistent_details[key2]:
2687 del self.inconsistent_details[key2]
2688
2689
2690
2691
2692 tmp_switch = dict(self.switch)
2693
2694
2695 to_check = [(c['changed_key'], c['new_changed_key_val']) \
2696 for k in self.inconsistent_details.values() for c in k
2697 if c['changed_key'] != key]
2698
2699 to_check.sort(lambda x, y: -1 if self.last_changed.index(x[0])>self.last_changed.index(y[0]) else 1)
2700
2701
2702 to_check = [(key, value)] + to_check
2703
2704 i = 0
2705 while len(to_check) and i < 50:
2706
2707
2708 i +=1
2709 key2, value2 = to_check.pop(0)
2710 if hasattr(self, 'consistency_%s' % key2):
2711 rules2 = dict([(key2, None) for key2 in self.switch])
2712 rules2.update(getattr(self, 'consistency_%s' % key2)(value, tmp_switch))
2713 else:
2714 rules = {}
2715 for key3,value3 in self.switch.items():
2716 if hasattr(self, 'consistency_%s_%s' % (key2,key3)):
2717 rules[key3] = getattr(self, 'consistency_%s_%s' % (key2,key3))(value2, value3)
2718 else:
2719 rules[key3] = None
2720
2721 for key, replacement in rules.items():
2722 if replacement:
2723 tmp_switch[key] = replacement
2724 to_check.append((key, replacement))
2725
2726
2727
2728 pos = {}
2729 for i, (key,value) in enumerate(to_check):
2730 pos[key] = i
2731 to_check_new = []
2732 for i, (key,value) in enumerate(to_check):
2733 if pos[key] == i:
2734 to_check_new.append((key,value))
2735 to_check = to_check_new
2736 if i>=50:
2737 logger.critical('Failed to find a consistent set of switch values.')
2738
2739
2740
2741 self.inconsistent_keys = {}
2742 for key2, value2 in tmp_switch.items():
2743 if value2 != self.switch[key2]:
2744
2745 if value2 == 'OFF' and not self.check_value(key2, 'OFF'):
2746 continue
2747 self.inconsistent_keys[key2] = value2
2748
2749
2750
2751
2752 green = '\x1b[32m%s\x1b[0m'
2753 yellow = '\x1b[33m%s\x1b[0m'
2754 red = '\x1b[31m%s\x1b[0m'
2755 bold = '\x1b[01m%s\x1b[0m'
2757
2758 if consistency and key in self.inconsistent_keys:
2759 return self.color_for_value(key, self.inconsistent_keys[key], consistency=False) +\
2760 u' \u21d0 '+ self.yellow % switch_value
2761
2762 if self.check_value(key, switch_value):
2763 if hasattr(self, 'color_for_%s' % key):
2764 return getattr(self, 'color_for_%s' % key)(switch_value)
2765 if switch_value in ['OFF']:
2766
2767 return self.red % switch_value
2768 else:
2769 return self.green % switch_value
2770 else:
2771 if ' ' in switch_value:
2772 return self.bold % switch_value
2773 else:
2774 return self.red % switch_value
2775
2777
2778 if hasattr(self, 'print_info_%s' % key):
2779 return getattr(self, 'print_info_%s' % key)
2780
2781
2782 try:
2783 ind = self.get_allowed(key).index(self.switch[key])
2784 except Exception, err:
2785 options = self.get_allowed(key)
2786 else:
2787 options = self.get_allowed(key)[ind:]+ self.get_allowed(key)[:ind]
2788
2789 info = '|'.join([v for v in options if v != self.switch[key]])
2790 if info == '':
2791 info = 'Please install module'
2792 return info
2793
2965
2967 """ create the question with correct formatting"""
2968
2969
2970
2971 try:
2972 nb_rows, nb_col = os.popen('stty size', 'r').read().split()
2973 nb_rows, nb_col = int(nb_rows), int(nb_col)
2974 except Exception,error:
2975 nb_rows, nb_col = 20, 80
2976
2977
2978 max_len_description = 0
2979 max_len_switch = 0
2980 max_len_name = 0
2981 max_len_add_info = 0
2982 max_len_potential_switch = 0
2983 max_nb_key = 1 + int(math.log10(len(self.to_control)))
2984
2985 for key, descrip in self.to_control:
2986 if len(descrip) > max_len_description: max_len_description = len(descrip)
2987 if len(key) > max_len_name: max_len_name = len(key)
2988 if key in self.inconsistent_keys:
2989 to_display = '%s < %s' % (self.switch[key], self.inconsistent_keys[key])
2990 else:
2991 to_display = self.switch[key]
2992 if len(to_display) > max_len_switch: max_len_switch=len(to_display)
2993
2994 info = self.print_info(key)
2995 if len(info)> max_len_add_info: max_len_add_info = len(info)
2996
2997 if self.get_allowed(key):
2998 max_k = max(len(k) for k in self.get_allowed(key))
2999 else:
3000 max_k = 0
3001 if max_k > max_len_potential_switch: max_len_potential_switch = max_k
3002
3003 upper_line, lower_line, f1, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3004 max_len_name, max_len_add_info,
3005 max_len_potential_switch, max_nb_key)
3006
3007 text = \
3008 ["The following switches determine which programs are run:",
3009 upper_line
3010 ]
3011
3012
3013
3014 for i,(key, descrip) in enumerate(self.to_control):
3015
3016
3017
3018 data_to_format = {'nb': i+1,
3019 'descrip': descrip,
3020 'name': key,
3021 'switch': self.color_for_value(key,self.switch[key]),
3022 'add_info': self.print_info(key),
3023 'switch_nc': self.switch[key],
3024 'strike_switch': u'\u0336'.join(' %s ' %self.switch[key].upper()) + u'\u0336',
3025 }
3026 if key in self.inconsistent_keys:
3027
3028 _,_,_, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3029 max_len_name, max_len_add_info,
3030 max_len_potential_switch, max_nb_key,
3031 key=key)
3032
3033 data_to_format['conflict_switch_nc'] = self.inconsistent_keys[key]
3034 data_to_format['conflict_switch'] = self.color_for_value(key,self.inconsistent_keys[key], consistency=False)
3035 text.append(f2 % data_to_format)
3036 else:
3037 text.append(f1 % data_to_format)
3038
3039
3040 text.append(lower_line)
3041
3042
3043 example = None
3044 for key in self.switch:
3045 if len(self.get_allowed(key)) > 1:
3046 for val in self.get_allowed(key):
3047 if val != self.switch[key]:
3048 example = (key, val)
3049 break
3050 else:
3051 continue
3052 break
3053
3054 if not example:
3055 example = ('KEY', 'VALUE')
3056
3057 text += \
3058 ["Either type the switch number (1 to %s) to change its setting," % len(self.to_control),
3059 "Set any switch explicitly (e.g. type '%s=%s' at the prompt)" % example,
3060 "Type 'help' for the list of all valid option",
3061 "Type '0', 'auto', 'done' or just press enter when you are done."]
3062
3063
3064 if len(text) > nb_rows:
3065
3066 to_remove = [ -2,
3067 -5,
3068 -4,
3069 -3,
3070 -1,
3071 ]
3072 to_remove = to_remove[:min(len(to_remove), len(text)-nb_rows)]
3073 text = [t for i,t in enumerate(text) if i-len(text) not in to_remove]
3074
3075 self.question = "\n".join(text)
3076 return self.question
3077
3078
3079
3080
3081
3082
3083
3084 -class CmdFile(file):
3085 """ a class for command input file -in order to debug cmd \n problem"""
3086
3093
3095 """readline method treating correctly a line whithout \n at the end
3096 (add it)
3097 """
3098 if self.lines:
3099 line = self.lines.pop(0)
3100 else:
3101 return ''
3102
3103 if line.endswith('\n'):
3104 return line
3105 else:
3106 return line + '\n'
3107
3110
3113