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 from __future__ import absolute_import
19 from __future__ import print_function
20 import logging
21 import math
22 import os
23 import pydoc
24 import re
25 import signal
26 import subprocess
27 import sys
28 import traceback
29 import six
30 if six.PY3:
31 import io
32 file = io.IOBase
33 from six.moves import map
34 from six.moves import range
35 from six.moves import input
36 try:
37 import readline
38 GNU_SPLITTING = ('GNU' in readline.__doc__)
39 except:
40 readline = None
41 GNU_SPLITTING = True
42
43
44 logger = logging.getLogger('cmdprint')
45 logger_stderr = logging.getLogger('fatalerror')
46 logger_tuto = logging.getLogger('tutorial')
47 logger_plugin = logging.getLogger('tutorial_plugin')
48
49 try:
50 import madgraph.various.misc as misc
51 from madgraph import MG5DIR, MadGraph5Error
52 MADEVENT = False
53 except ImportError as error:
54 try:
55 import internal.misc as misc
56 except:
57 raise error
58
59 MADEVENT = True
60
61
62 pjoin = os.path.join
65 """Class for run-time error"""
66
67 -def debug(debug_only=True):
68
69 def deco_debug(f):
70
71 if debug_only and not __debug__:
72 return f
73
74 def deco_f(*args, **opt):
75 try:
76 return f(*args, **opt)
77 except Exception as error:
78 logger.error(error)
79 logger.error(traceback.print_exc(file=sys.stdout))
80 return
81 return deco_f
82 return deco_debug
83
84 import string
85
86
87 __all__ = ["Cmd"]
88 PROMPT = '(Cmd) '
89 IDENTCHARS = string.ascii_letters + string.digits + '_'
91 """A simple framework for writing line-oriented command interpreters.
92
93 These are often useful for test harnesses, administrative tools, and
94 prototypes that will later be wrapped in a more sophisticated interface.
95
96 A Cmd instance or subclass instance is a line-oriented interpreter
97 framework. There is no good reason to instantiate Cmd itself; rather,
98 it's useful as a superclass of an interpreter class you define yourself
99 in order to inherit Cmd's methods and encapsulate action methods.
100
101 """
102 prompt = PROMPT
103 identchars = IDENTCHARS
104 ruler = '='
105 lastcmd = ''
106 intro = None
107 doc_leader = ""
108 doc_header = "Documented commands (type help <topic>):"
109 misc_header = "Miscellaneous help topics:"
110 undoc_header = "Undocumented commands:"
111 nohelp = "*** No help on %s"
112 use_rawinput = 1
113
114 - def __init__(self, completekey='tab', stdin=None, stdout=None,**opt):
115 """Instantiate a line-oriented interpreter framework.
116
117 The optional argument 'completekey' is the readline name of a
118 completion key; it defaults to the Tab key. If completekey is
119 not None and the readline module is available, command completion
120 is done automatically. The optional arguments stdin and stdout
121 specify alternate input and output file objects; if not specified,
122 sys.stdin and sys.stdout are used.
123
124 """
125 import sys
126 if stdin is not None:
127 self.stdin = stdin
128 else:
129 self.stdin = sys.stdin
130 if stdout is not None:
131 self.stdout = stdout
132 else:
133 self.stdout = sys.stdout
134 self.cmdqueue = []
135 self.completekey = completekey
136 self.cmd_options = opt
137
139 """Repeatedly issue a prompt, accept input, parse an initial prefix
140 off the received input, and dispatch to action methods, passing them
141 the remainder of the line as argument.
142
143 """
144
145 self.preloop()
146 if self.use_rawinput and self.completekey:
147 try:
148 import readline
149 self.old_completer = readline.get_completer()
150 readline.set_completer(self.complete)
151 readline.parse_and_bind(self.completekey+": complete")
152 except ImportError:
153 pass
154 try:
155 if intro is not None:
156 self.intro = intro
157 if self.intro:
158 self.stdout.write(str(self.intro)+"\n")
159 stop = None
160 while not stop:
161 if self.cmdqueue:
162 line = self.cmdqueue.pop(0)
163 else:
164 if self.use_rawinput:
165 try:
166 line = input(self.prompt)
167 except EOFError:
168 line = 'EOF'
169 else:
170 self.stdout.write(self.prompt)
171 self.stdout.flush()
172 line = self.stdin.readline()
173 if not len(line):
174 line = 'EOF'
175 else:
176 line = line.rstrip('\r\n')
177 line = self.precmd(line)
178 stop = self.onecmd(line)
179 stop = self.postcmd(stop, line)
180 self.postloop()
181 finally:
182 if self.use_rawinput and self.completekey:
183 try:
184 import readline
185 readline.set_completer(self.old_completer)
186 except ImportError:
187 pass
188
189
191 """Hook method executed just before the command line is
192 interpreted, but after the input prompt is generated and issued.
193
194 """
195 return line
196
197 - def postcmd(self, stop, line):
198 """Hook method executed just after a command dispatch is finished."""
199 return stop
200
202 """Hook method executed once when the cmdloop() method is called."""
203 pass
204
205 - def postloop(self):
206 """Hook method executed once when the cmdloop() method is about to
207 return.
208
209 """
210 pass
211
213 """Parse the line into a command name and a string containing
214 the arguments. Returns a tuple containing (command, args, line).
215 'command' and 'args' may be None if the line couldn't be parsed.
216 """
217 line = line.strip()
218 if not line:
219 return None, None, line
220 elif line[0] == '?':
221 line = 'help ' + line[1:]
222 elif line[0] == '!':
223 if hasattr(self, 'do_shell'):
224 line = 'shell ' + line[1:]
225 else:
226 return None, None, line
227 i, n = 0, len(line)
228 while i < n and line[i] in self.identchars: i = i+1
229 cmd, arg = line[:i], line[i:].strip()
230 return cmd, arg, line
231
233 """Interpret the argument as though it had been typed in response
234 to the prompt.
235
236 This may be overridden, but should not normally need to be;
237 see the precmd() and postcmd() methods for useful execution hooks.
238 The return value is a flag indicating whether interpretation of
239 commands by the interpreter should stop.
240
241 """
242 cmd, arg, line = self.parseline(line)
243 if not line:
244 return self.emptyline()
245 if cmd is None:
246 return self.default(line)
247 self.lastcmd = line
248 if cmd == '':
249 return self.default(line)
250 else:
251 try:
252 func = getattr(self, 'do_' + cmd)
253 except AttributeError:
254 return self.default(line)
255 return func(arg)
256
258 """Called when an empty line is entered in response to the prompt.
259
260 If this method is not overridden, it repeats the last nonempty
261 command entered.
262
263 """
264 if self.lastcmd:
265 return self.onecmd(self.lastcmd)
266
268 """Called on an input line when the command prefix is not recognized.
269
270 If this method is not overridden, it prints an error message and
271 returns.
272
273 """
274 self.stdout.write('*** Unknown syntax: %s\n'%line)
275
277 """Method called to complete an input line when no command-specific
278 complete_*() method is available.
279
280 By default, it returns an empty list.
281
282 """
283 return []
284
286 dotext = 'do_'+text
287
288 done = set()
289 out = []
290
291 for a in self.get_names():
292 if a.startswith(dotext) and a not in done and not done.add(a):
293
294
295 if ('_' not in a[3:] or '%s%s' %(dotext,a[3:].split('_',1)[0]) not in done):
296 done.add(a)
297 out.append(a[3:])
298 return out
299
300 return [a[3:] for a in self.get_names()
301 if a.startswith(dotext) and a not in done and not done.add(a)
302 and ('_' not in a[3:] or '%s%s' %(dotext,a[3:].split('_',1)[0]) not in done)
303 ]
304
306 """Return the next possible completion for 'text'.
307
308 If a command has not been entered, then complete against command list.
309 Otherwise try to call complete_<command> to get list of completions.
310 """
311 if state == 0:
312 import readline
313 origline = readline.get_line_buffer()
314 line = origline.lstrip()
315 stripped = len(origline) - len(line)
316 begidx = readline.get_begidx() - stripped
317 endidx = readline.get_endidx() - stripped
318 if begidx>0:
319 cmd, args, foo = self.parseline(line)
320 if cmd == '':
321 compfunc = self.completedefault
322 else:
323 try:
324 compfunc = getattr(self, 'complete_' + cmd)
325 except AttributeError:
326 compfunc = self.completedefault
327 else:
328 compfunc = self.completenames
329 self.completion_matches = compfunc(text, line, begidx, endidx)
330 try:
331 return self.completion_matches[state]
332 except IndexError:
333 return None
334
336
337
338 names = []
339 classes = [self.__class__]
340 while classes:
341 aclass = classes.pop(0)
342 if aclass.__bases__:
343 classes = classes + list(aclass.__bases__)
344 names = names + dir(aclass)
345 return names
346
349
351 if arg:
352
353 try:
354 func = getattr(self, 'help_' + arg)
355 except AttributeError:
356 try:
357 doc=getattr(self, 'do_' + arg).__doc__
358 if doc:
359 self.stdout.write("%s\n"%str(doc))
360 return
361 except AttributeError:
362 pass
363 self.stdout.write("%s\n"%str(self.nohelp % (arg,)))
364 return
365 func()
366 else:
367 names = self.get_names()
368 cmds_doc = []
369 cmds_undoc = []
370 help = {}
371 for name in names:
372 if name[:5] == 'help_':
373 help[name[5:]]=1
374 names.sort()
375
376 prevname = ''
377 for name in names:
378 if name[:3] == 'do_':
379 if name == prevname:
380 continue
381 prevname = name
382 cmd=name[3:]
383 if cmd in help:
384 cmds_doc.append(cmd)
385 del help[cmd]
386 elif getattr(self, name).__doc__:
387 cmds_doc.append(cmd)
388 else:
389 cmds_undoc.append(cmd)
390 self.stdout.write("%s\n"%str(self.doc_leader))
391 self.print_topics(self.doc_header, cmds_doc, 15,80)
392 self.print_topics(self.misc_header, list(help.keys()),15,80)
393 self.print_topics(self.undoc_header, cmds_undoc, 15,80)
394
402
404 """Display a list of strings as a compact set of columns.
405
406 Each column is only as wide as necessary.
407 Columns are separated by two spaces (one was not legible enough).
408 """
409 if not list:
410 self.stdout.write("<empty>\n")
411 return
412 nonstrings = [i for i in range(len(list))
413 if not isinstance(list[i], str)]
414 if nonstrings:
415 raise TypeError("list[i] not a string for i in %s" %
416 ", ".join(map(str, nonstrings)))
417 size = len(list)
418 if size == 1:
419 self.stdout.write('%s\n'%str(list[0]))
420 return
421
422 for nrows in range(1, len(list)):
423 ncols = (size+nrows-1) // nrows
424 colwidths = []
425 totwidth = -2
426 for col in range(ncols):
427 colwidth = 0
428 for row in range(nrows):
429 i = row + nrows*col
430 if i >= size:
431 break
432 x = list[i]
433 colwidth = max(colwidth, len(x))
434 colwidths.append(colwidth)
435 totwidth += colwidth + 2
436 if totwidth > displaywidth:
437 break
438 if totwidth <= displaywidth:
439 break
440 else:
441 nrows = len(list)
442 ncols = 1
443 colwidths = [0]
444 for row in range(nrows):
445 texts = []
446 for col in range(ncols):
447 i = row + nrows*col
448 if i >= size:
449 x = ""
450 else:
451 x = list[i]
452 texts.append(x)
453 while texts and not texts[-1]:
454 del texts[-1]
455 for col in range(len(texts)):
456 texts[col] = texts[col].ljust(colwidths[col])
457 self.stdout.write("%s\n"%str(" ".join(texts)))
458
459
460
461
462
463
464
465 -class BasicCmd(OriginalCmd):
466 """Simple extension for the readline"""
467
469 """ This has been refactorized here so that it can be called when another
470 program called by MG5 (such as MadAnalysis5) changes this attribute of readline"""
471 if readline:
472 if not 'libedit' in readline.__doc__:
473 readline.set_completion_display_matches_hook(self.print_suggestions)
474 else:
475 readline.set_completion_display_matches_hook()
476
480
482 """convert the multiple category in a formatted list understand by our
483 specific readline parser"""
484
485 if not formatting:
486 return dico
487
488 if 'libedit' in readline.__doc__:
489
490 out = []
491 for name, opt in dico.items():
492 out += opt
493 return list(set(out))
494
495
496 if not forceCategory and all(len(s) <= 1 for s in dico.values() ):
497 values = set((s[0] for s in dico.values() if len(s)==1))
498 if len(values) == 1:
499 return values
500
501
502 out = []
503 valid=0
504
505 for name, opt in dico.items():
506 if not opt:
507 continue
508 name = name.replace(' ', '_')
509 valid += 1
510 out.append(opt[0].rstrip()+'@@'+name+'@@')
511
512 d = {}
513 for x in opt:
514 d[x] = 1
515 opt = list(d.keys())
516 opt.sort()
517 out += opt
518
519 if not forceCategory and valid == 1:
520 out = out[1:]
521
522 return out
523
524 @debug()
526 """print auto-completions by category"""
527 if not hasattr(self, 'completion_prefix'):
528 self.completion_prefix = ''
529 longest_match_length += len(self.completion_prefix)
530 try:
531 if len(matches) == 1:
532 self.stdout.write(matches[0]+' ')
533 return
534 self.stdout.write('\n')
535 l2 = [a[-2:] for a in matches]
536 if '@@' in l2:
537 nb_column = self.getTerminalSize()//(longest_match_length+1)
538 pos=0
539 for val in self.completion_matches:
540 if val.endswith('@@'):
541 category = val.rsplit('@@',2)[1]
542 category = category.replace('_',' ')
543 self.stdout.write('\n %s:\n%s\n' % (category, '=' * (len(category)+2)))
544 start = 0
545 pos = 0
546 continue
547 elif pos and pos % nb_column ==0:
548 self.stdout.write('\n')
549 self.stdout.write(self.completion_prefix + val + \
550 ' ' * (longest_match_length +1 -len(val)))
551 pos +=1
552 self.stdout.write('\n')
553 else:
554
555 nb_column = self.getTerminalSize()//(longest_match_length+1)
556 for i,val in enumerate(matches):
557 if i and i%nb_column ==0:
558 self.stdout.write('\n')
559 self.stdout.write(self.completion_prefix + val + \
560 ' ' * (longest_match_length +1 -len(val)))
561 self.stdout.write('\n')
562
563 self.stdout.write(self.prompt+readline.get_line_buffer())
564 self.stdout.flush()
565 except Exception as error:
566 if __debug__:
567 logger.error(error)
568
570 def ioctl_GWINSZ(fd):
571 try:
572 import fcntl, termios, struct
573 cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
574 '1234'))
575 except Exception:
576 return None
577 return cr
578 cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
579 if not cr:
580 try:
581 fd = os.open(os.ctermid(), os.O_RDONLY)
582 cr = ioctl_GWINSZ(fd)
583 os.close(fd)
584 except Exception:
585 pass
586 if not cr:
587 try:
588 cr = (os.environ['LINES'], os.environ['COLUMNS'])
589 except Exception:
590 cr = (25, 80)
591 return int(cr[1])
592
594 """Return the next possible completion for 'text'.
595 If a command has not been entered, then complete against command list.
596 Otherwise try to call complete_<command> to get list of completions.
597 """
598 if state == 0:
599 import readline
600 origline = readline.get_line_buffer()
601 line = origline.lstrip()
602 stripped = len(origline) - len(line)
603 begidx = readline.get_begidx() - stripped
604 endidx = readline.get_endidx() - stripped
605
606 if ';' in line:
607 begin, line = line.rsplit(';',1)
608 begidx = begidx - len(begin) - 1
609 endidx = endidx - len(begin) - 1
610 if line[:begidx] == ' ' * begidx:
611 begidx=0
612
613 if begidx>0:
614 cmd, args, foo = self.parseline(line)
615 if cmd == '':
616 compfunc = self.completedefault
617 else:
618 try:
619 compfunc = getattr(self, 'complete_' + cmd)
620 except AttributeError as error:
621 compfunc = self.completedefault
622 except Exception as error:
623 misc.sprint(error)
624 else:
625 compfunc = self.completenames
626
627
628 if line and begidx > 2 and line[begidx-2:begidx] == '\ ':
629 Ntext = line.split(os.path.sep)[-1]
630 self.completion_prefix = Ntext.rsplit('\ ', 1)[0] + '\ '
631 to_rm = len(self.completion_prefix) - 1
632 Nbegidx = len(line.rsplit(os.path.sep, 1)[0]) + 1
633 data = compfunc(Ntext.replace('\ ', ' '), line, Nbegidx, endidx)
634 self.completion_matches = [p[to_rm:] for p in data
635 if len(p)>to_rm]
636
637 elif line and line[begidx-1] in ['-',"=",':']:
638 try:
639 sep = line[begidx-1]
640 Ntext = line.split()[-1]
641 self.completion_prefix = Ntext.rsplit(sep,1)[0] + sep
642 to_rm = len(self.completion_prefix)
643 Nbegidx = len(line.rsplit(None, 1)[0])
644 data = compfunc(Ntext, line, Nbegidx, endidx)
645 self.completion_matches = [p[to_rm:] for p in data
646 if len(p)>to_rm]
647 except Exception as error:
648 print(error)
649 else:
650 self.completion_prefix = ''
651 self.completion_matches = compfunc(text, line, begidx, endidx)
652
653 self.completion_matches = [ l if l[-1] in [' ','@','=',os.path.sep]
654 else ((l + ' ') if not l.endswith('\\$') else l[:-2])
655 for l in self.completion_matches if l]
656
657 try:
658 return self.completion_matches[state]
659 except IndexError as error:
660
661
662
663 return None
664
665 @staticmethod
667 """Split a line of arguments"""
668
669 split = re.findall(r"(?:[^\s'\"]|(?:'|\")(?:\\.|[^\"'])*(?:\"|'))+",line)
670
671 out=[]
672 tmp=''
673 for data in split:
674 if data[-1] == '\\':
675 tmp += data[:-1]+' '
676 elif tmp:
677 tmp += data
678 tmp = os.path.expanduser(os.path.expandvars(tmp))
679 out.append(tmp)
680
681
682 tmp = ''
683 else:
684 out.append(data)
685 return out
686
687 @staticmethod
689 """Propose completions of text in list"""
690
691 if not text:
692 completions = list
693 else:
694 completions = [ f
695 for f in list
696 if f.startswith(text)
697 ]
698
699 return completions
700
701
702 @staticmethod
703 - def path_completion(text, base_dir = None, only_dirs = False,
704 relative=True):
705 """Propose completions of text to compose a valid path"""
706
707 if base_dir is None:
708 base_dir = os.getcwd()
709 base_dir = os.path.expanduser(os.path.expandvars(base_dir))
710
711 if text == '~':
712 text = '~/'
713 prefix, text = os.path.split(text)
714 prefix = os.path.expanduser(os.path.expandvars(prefix))
715 base_dir = os.path.join(base_dir, prefix)
716 if prefix:
717 prefix += os.path.sep
718
719 if only_dirs:
720 completion = [prefix + f + os.path.sep
721 for f in os.listdir(base_dir)
722 if f.startswith(text) and \
723 os.path.isdir(os.path.join(base_dir, f)) and \
724 (not f.startswith('.') or text.startswith('.'))
725 ]
726 else:
727 completion = [ prefix + f
728 for f in os.listdir(base_dir)
729 if f.startswith(text) and \
730 os.path.isfile(os.path.join(base_dir, f)) and \
731 (not f.startswith('.') or text.startswith('.'))
732 ]
733
734 completion = completion + \
735 [prefix + f + os.path.sep
736 for f in os.listdir(base_dir)
737 if f.startswith(text) and \
738 os.path.isdir(os.path.join(base_dir, f)) and \
739 (not f.startswith('.') or text.startswith('.'))
740 ]
741
742 if relative:
743 completion += [prefix + f for f in ['.'+os.path.sep, '..'+os.path.sep] if \
744 f.startswith(text) and not prefix.startswith('.')]
745
746 completion = [a.replace(' ','\ ') for a in completion]
747 return completion
748
753 """Extension of the cmd object for only the check command"""
754
755 - def check_history(self, args):
756 """check the validity of line"""
757
758 if len(args) > 1:
759 self.help_history()
760 raise self.InvalidCmd('\"history\" command takes at most one argument')
761
762 if not len(args):
763 return
764
765 if args[0] =='.':
766 if not self._export_dir:
767 raise self.InvalidCmd("No default directory is defined for \'.\' option")
768 elif args[0] != 'clean':
769 dirpath = os.path.dirname(args[0])
770 if dirpath and not os.path.exists(dirpath) or \
771 os.path.isdir(args[0]):
772 raise self.InvalidCmd("invalid path %s " % dirpath)
773
775 """check that the line is compatible with save options"""
776
777 if len(args) > 2:
778 self.help_save()
779 raise self.InvalidCmd('too many arguments for save command.')
780
781 if len(args) == 2:
782 if args[0] != 'options':
783 self.help_save()
784 raise self.InvalidCmd('\'%s\' is not recognized as first argument.' % \
785 args[0])
786 else:
787 args.pop(0)
788
790 """Extension of the cmd object for only the help command"""
791
793 logger.info("-- terminates the application",'$MG:color:BLUE')
794 logger.info("syntax: quit",'$MG:BOLD')
795
796 help_EOF = help_quit
797
798 - def help_history(self):
799 logger.info("-- interact with the command history.",'$MG:color:BLUE')
800 logger.info("syntax: history [FILEPATH|clean|.] ",'$MG:BOLD')
801 logger.info(" > If FILEPATH is \'.\' and \'output\' is done,")
802 logger.info(" Cards/proc_card_mg5.dat will be used.")
803 logger.info(" > If FILEPATH is omitted, the history will be output to stdout.")
804 logger.info(" \"clean\" will remove all entries from the history.")
805
807 logger.info("-- access to the in-line help",'$MG:color:BLUE')
808 logger.info("syntax: help",'$MG:BOLD')
809
811 """help text for save"""
812 logger.info("-- save options configuration to filepath.",'$MG:color:BLUE')
813 logger.info("syntax: save [options] [FILEPATH]",'$MG:BOLD')
814
816 """help for display command"""
817 logger.info("-- display a the status of various internal state variables",'$MG:color:BLUE')
818 logger.info("syntax: display " + "|".join(self._display_opts),'$MG:BOLD')
819
828
829 - def complete_history(self, text, line, begidx, endidx):
830 "Complete the history command"
831
832 args = self.split_arg(line[0:begidx])
833
834
835 if args[-1].endswith(os.path.sep):
836 return self.path_completion(text,
837 os.path.join('.',*[a for a in args \
838 if a.endswith(os.path.sep)]))
839
840 if len(args) == 1:
841 return self.path_completion(text)
842
861
862 -class Cmd(CheckCmd, HelpCmd, CompleteCmd, BasicCmd):
863 """Extension of the cmd.Cmd command line.
864 This extensions supports line breaking, history, comments,
865 internal call to cmdline, path completion,...
866 this class should be MG5 independent"""
867
868
869 next_possibility = {}
870 history_header = ""
871
872 _display_opts = ['options','variable']
873 allow_notification_center = True
874
876 """expected error for wrong command"""
877 pass
878
879 ConfigurationError = InvalidCmd
880
881 debug_output = 'debug'
882 error_debug = """Please report this bug to developers\n
883 More information is found in '%(debug)s'.\n
884 Please attach this file to your report."""
885 config_debug = error_debug
886
887 keyboard_stop_msg = """stopping all current operation
888 in order to quit the program please enter exit"""
889
890 if MADEVENT:
891 plugin_path = []
892 else:
893 plugin_path = [pjoin(MG5DIR, 'PLUGIN')]
894 if 'PYTHONPATH' in os.environ:
895 for PluginCandidate in os.environ['PYTHONPATH'].split(':'):
896 try:
897 dirlist = os.listdir(PluginCandidate)
898 except OSError:
899 continue
900 for onedir in dirlist:
901 if onedir == 'MG5aMC_PLUGIN':
902 plugin_path.append(pjoin(PluginCandidate, 'MG5aMC_PLUGIN'))
903 break
904 else:
905 continue
906 break
907
909 """Init history and line continuation"""
910
911 self.log = True
912 self.history = []
913 self.save_line = ''
914 super(Cmd, self).__init__(*arg, **opt)
915 self.__initpos = os.path.abspath(os.getcwd())
916 self.child = None
917 self.mother = None
918 self.inputfile = None
919 self.haspiping = not sys.stdin.isatty()
920 self.stored_line = ''
921
922 if not hasattr(self, 'helporder'):
923 self.helporder = ['Documented commands']
924
926 """Hook method executed once when the cmdloop() method is called."""
927 if self.completekey:
928 try:
929 import readline
930 self.old_completer = readline.get_completer()
931 readline.set_completer(self.complete)
932 readline.parse_and_bind(self.completekey+": complete")
933 except ImportError:
934 readline = None
935 pass
936 if readline and not 'libedit' in readline.__doc__:
937 readline.set_completion_display_matches_hook(self.print_suggestions)
938
939
941
942 self.preloop()
943 if intro is not None:
944 self.intro = intro
945 if self.intro:
946 print(self.intro)
947 stop = None
948 while not stop:
949 if self.cmdqueue:
950 line = self.cmdqueue[0]
951 del self.cmdqueue[0]
952 else:
953 if self.use_rawinput:
954 try:
955 line = input(self.prompt)
956 except EOFError:
957 line = 'EOF'
958 else:
959 sys.stdout.write(self.prompt)
960 sys.stdout.flush()
961 line = sys.stdin.readline()
962 if not len(line):
963 line = 'EOF'
964 else:
965 line = line[:-1]
966 try:
967 line = self.precmd(line)
968 stop = self.onecmd(line)
969 except BaseException as error:
970 self.error_handling(error, line)
971 if isinstance(error, KeyboardInterrupt):
972 stop = True
973 finally:
974 stop = self.postcmd(stop, line)
975 self.postloop()
976
978 """avoid to have html opening / notification"""
979 self.allow_notification_center = False
980 try:
981 self.options['automatic_html_opening'] = False
982 self.options['notification_center'] = False
983
984 except:
985 pass
986
987
989 """ A suite of additional function needed for in the cmd
990 this implement history, line breaking, comment treatment,...
991 """
992
993 if not line:
994 return line
995
996
997 if self.save_line:
998 line = self.save_line + line
999 self.save_line = ''
1000
1001 line = line.lstrip()
1002
1003 if line.endswith('\\'):
1004 self.save_line = line[:-1]
1005 return ''
1006
1007
1008 if '#' in line:
1009 line = line.split('#')[0]
1010
1011
1012 if ';' in line:
1013 lines = line.split(';')
1014 for subline in lines:
1015 if not (subline.startswith("history") or subline.startswith('help') \
1016 or subline.startswith('#*')):
1017 self.history.append(subline)
1018 stop = self.onecmd_orig(subline)
1019 stop = self.postcmd(stop, subline)
1020 return ''
1021
1022
1023 self.history.append(line)
1024 return line
1025
1026 - def postcmd(self,stop, line):
1027 """ finishing a command
1028 This looks if the command add a special post part."""
1029
1030 if line.strip():
1031 try:
1032 cmd, subline = line.split(None, 1)
1033 except ValueError:
1034 pass
1035 else:
1036 if hasattr(self,'post_%s' %cmd):
1037 stop = getattr(self, 'post_%s' % cmd)(stop, subline)
1038 return stop
1039
1064
1065
1066
1067
1068 - def ask(self, question, default, choices=[], path_msg=None,
1069 timeout = True, fct_timeout=None, ask_class=None, alias={},
1070 first_cmd=None, text_format='4', force=False,
1071 return_instance=False, **opt):
1072 """ ask a question with some pre-define possibility
1073 path info is
1074 """
1075
1076 if path_msg:
1077 path_msg = [path_msg]
1078 else:
1079 path_msg = []
1080
1081 if timeout is True:
1082 try:
1083 timeout = self.options['timeout']
1084 except Exception:
1085 pass
1086
1087
1088 if choices + path_msg:
1089 question += ' ['
1090 question += "\033[%sm%s\033[0m, " % (text_format, default)
1091 for data in choices[:9] + path_msg:
1092 if default == data:
1093 continue
1094 else:
1095 question += "%s, " % data
1096
1097 if len(choices) > 9:
1098 question += '... , '
1099 question = question[:-2]+']'
1100 else:
1101 question += "[\033[%sm%s\033[0m] " % (text_format, default)
1102 if ask_class:
1103 obj = ask_class
1104 elif path_msg:
1105 obj = OneLinePathCompletion
1106 else:
1107 obj = SmartQuestion
1108
1109 if alias:
1110 choices += list(alias.keys())
1111
1112 question_instance = obj(question, allow_arg=choices, default=default,
1113 mother_interface=self, **opt)
1114
1115 if first_cmd:
1116 if isinstance(first_cmd, str):
1117 question_instance.onecmd(first_cmd)
1118 else:
1119 for line in first_cmd:
1120 question_instance.onecmd(line)
1121 if not self.haspiping:
1122 if hasattr(obj, "haspiping"):
1123 obj.haspiping = self.haspiping
1124
1125 if force:
1126 answer = default
1127 else:
1128 answer = self.check_answer_in_input_file(question_instance, default, path_msg)
1129 if answer is not None:
1130 if answer in alias:
1131 answer = alias[answer]
1132 if ask_class:
1133 line=answer
1134 answer = question_instance.default(line)
1135 question_instance.postcmd(answer, line)
1136 if not return_instance:
1137 return question_instance.answer
1138 else:
1139 return question_instance.answer , question_instance
1140 if hasattr(question_instance, 'check_answer_consistency'):
1141 question_instance.check_answer_consistency()
1142 if not return_instance:
1143 return answer
1144 else:
1145 return answer, question_instance
1146
1147 question = question_instance.question
1148 if not force:
1149 value = Cmd.timed_input(question, default, timeout=timeout,
1150 fct=question_instance, fct_timeout=fct_timeout)
1151 else:
1152 value = default
1153
1154 try:
1155 if value in alias:
1156 value = alias[value]
1157 except TypeError:
1158 pass
1159
1160 if value == default and ask_class:
1161 value = question_instance.default(default)
1162
1163 if not return_instance:
1164 return value
1165 else:
1166 return value, question_instance
1167
1177
1178
1180 """check import command"""
1181
1182 if '-f' in args:
1183 self.force = True
1184 args.remove('-f')
1185 if args[0] != 'command':
1186 args.set(0, 'command')
1187 if len(args) != 2:
1188 raise self.InvalidCmd('import command requires one filepath argument')
1189 if not os.path.exists(args[1]):
1190 raise 'No such file or directory %s' % args[1]
1191
1192
1276
1278 """store a line of the input file which should be executed by the higher mother"""
1279
1280 if self.mother:
1281 self.mother.store_line(line)
1282 else:
1283 self.stored_line = line
1284
1286 """return stored line and clean it"""
1287 if self.mother:
1288 value = self.mother.get_stored_line()
1289 self.mother.stored_line = None
1290 else:
1291 value = self.stored_line
1292 self.stored_line = None
1293 return value
1294
1295
1296
1298 """ """
1299
1300 if self.child:
1301 return self.child.nice_error_handling(error, line)
1302
1303 os.chdir(self.__initpos)
1304
1305 self.log = False
1306 if os.path.exists(self.debug_output):
1307 os.remove(self.debug_output)
1308 try:
1309 super(Cmd,self).onecmd('history %s' % self.debug_output.replace(' ', '\ '))
1310 except Exception as error:
1311 logger.error(error)
1312
1313 debug_file = open(self.debug_output, 'a')
1314 traceback.print_exc(file=debug_file)
1315 if hasattr(error, 'filename'):
1316 debug_file.write("Related File: %s\n" % error.filename)
1317
1318 if self.history and line == self.history[-1]:
1319 error_text = 'Command \"%s\" interrupted with error:\n' % line
1320 elif self.history:
1321 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
1322 error_text += '\"%s\" with error:\n' % self.history[-1]
1323 else:
1324 error_text = ''
1325 error_text += '%s : %s\n' % (error.__class__.__name__,
1326 str(error).replace('\n','\n\t'))
1327 error_text += self.error_debug % {'debug':self.debug_output}
1328 logger_stderr.critical(error_text)
1329
1330
1331
1332 try:
1333 self.do_display('options', debug_file)
1334 except Exception as error:
1335 debug_file.write('Fail to write options with error %s' % error)
1336
1337
1338 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']:
1339 try:
1340 ff = open(pjoin(self.me_dir, 'Cards', card))
1341 debug_file.write(ff.read())
1342 ff.close()
1343 except Exception:
1344 pass
1345
1346 if hasattr(self, 'options') and 'crash_on_error' in self.options:
1347 if self.options['crash_on_error'] is True:
1348 logger.info('stop computation due to crash_on_error=True')
1349 raise
1350 sys.exit(str(error))
1351 elif self.options['crash_on_error'] == 'never':
1352 return False
1353
1354
1355 if self.use_rawinput == False or self.inputfile:
1356 return True
1357 elif self.mother:
1358 if self.mother.use_rawinput is False:
1359 return True
1360
1361 elif self.mother.mother:
1362 if self.mother.mother.use_rawinput is False:
1363 return True
1364
1365 return False
1366
1367
1368
1370 if self.child:
1371 return self.child.nice_user_error(error, line)
1372
1373
1374 os.chdir(self.__initpos)
1375 if not self.history or line == self.history[-1]:
1376 error_text = 'Command \"%s\" interrupted with error:\n' % line
1377 else:
1378 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
1379 error_text += '\"%s\" with error:\n' % self.history[-1]
1380 error_text += '%s : %s' % (error.__class__.__name__,
1381 str(error).replace('\n','\n\t'))
1382 logger_stderr.error(error_text)
1383
1384 if hasattr(self, 'options') and 'crash_on_error' in self.options:
1385 if self.options['crash_on_error'] is True:
1386 logger.info('stop computation due to crash_on_error=True')
1387 sys.exit(str(error))
1388 elif self.options['crash_on_error'] == 'never':
1389 self.history.pop()
1390 return False
1391
1392
1393 if self.use_rawinput == False or self.inputfile:
1394 return True
1395 elif self.mother:
1396 if self.mother.use_rawinput is False:
1397 return True
1398 elif self.mother.mother:
1399 if self.mother.mother.use_rawinput is False:
1400 return True
1401
1402
1403 self.history.pop()
1404 return False
1405
1407 if self.child:
1408 return self.child.nice_user_error(error, line)
1409
1410
1411 os.chdir(self.__initpos)
1412 if not self.history or line == self.history[-1]:
1413 error_text = 'Error detected in \"%s\"\n' % line
1414 else:
1415 error_text = 'Error detected in sub-command %s\n' % self.history[-1]
1416 error_text += 'write debug file %s \n' % self.debug_output
1417 self.log = False
1418 super(Cmd,self).onecmd('history %s' % self.debug_output)
1419 debug_file = open(self.debug_output, 'a')
1420 traceback.print_exc(file=debug_file)
1421 try:
1422 error = error.encode('utf-8','backslashreplace')
1423 except:
1424 error = str(error)
1425 error_text += self.config_debug % {'debug' :self.debug_output}
1426 error_text += '%s : %s' % (error.__class__.__name__,
1427 str(error).replace('\n','\n\t'))
1428 logger_stderr.error(error_text)
1429
1430
1431 try:
1432 self.do_display('options', debug_file)
1433 except Exception as error:
1434 debug_file.write('Fail to write options with error %s' % error)
1435
1436 if hasattr(self, 'options') and 'crash_on_error' in self.options:
1437 if self.options['crash_on_error'] is True:
1438 logger.info('stop computation due to crash_on_error=True')
1439 sys.exit(str(error))
1440 elif self.options['crash_on_error'] == 'never':
1441 if self.history:
1442 self.history.pop()
1443 return False
1444
1445
1446
1447
1448 if self.use_rawinput == False or self.inputfile:
1449 return True
1450 elif self.mother:
1451 if self.mother.use_rawinput is False:
1452 return True
1453 elif self.mother.mother:
1454 if self.mother.mother.use_rawinput is False:
1455 return True
1456
1457
1458 if self.history:
1459 self.history.pop()
1460 return False
1461
1463 """Interpret the argument as though it had been typed in response
1464 to the prompt.
1465
1466 The return value is a flag indicating whether interpretation of
1467 commands by the interpreter should stop.
1468
1469 This allow to pass extra argument for internal call.
1470 """
1471 if '~/' in line and 'HOME' in os.environ:
1472 line = line.replace('~/', '%s/' % os.environ['HOME'])
1473 if '#' in line:
1474 line = line.split('#')[0]
1475
1476 line = os.path.expandvars(line)
1477 cmd, arg, line = self.parseline(line)
1478 if not line:
1479 return self.emptyline()
1480 if cmd is None:
1481 return self.default(line)
1482 self.lastcmd = line
1483 if cmd == '':
1484 return self.default(line)
1485 else:
1486 try:
1487 func = getattr(self, 'do_' + cmd)
1488 except AttributeError:
1489 return self.default(line)
1490 return func(arg, **opt)
1491
1534
1535
1536
1537 - def onecmd(self, line, **opt):
1538 """catch all error and stop properly command accordingly"""
1539
1540 try:
1541 return self.onecmd_orig(line, **opt)
1542 except BaseException as error:
1543 return self.error_handling(error, line)
1544
1545
1547 """action to perform to close nicely on a keyboard interupt"""
1548 pass
1549
1550 - def exec_cmd(self, line, errorhandling=False, printcmd=True,
1551 precmd=False, postcmd=True,
1552 child=True, **opt):
1574
1576 """for third party call, call the line with pre and postfix treatment
1577 with global error handling"""
1578
1579 return self.exec_cmd(line, errorhandling=True, precmd=True)
1580
1582 """If empty line, do nothing. Default is repeat previous command."""
1583 pass
1584
1585 - def default(self, line, log=True):
1586 """Default action if line is not recognized"""
1587
1588
1589 if log:
1590 logger.warning("Command \"%s\" not recognized, please try again" % \
1591 line.split()[0])
1592 if line.strip() in ['q', '.q', 'stop']:
1593 logger.info("If you want to quit mg5 please type \"exit\".")
1594
1595 if self.history and self.history[-1] == line:
1596 self.history.pop()
1597
1598
1599 - def do_history(self, line):
1600 """write in a file the suite of command that was used"""
1601
1602 args = self.split_arg(line)
1603
1604 self.check_history(args)
1605
1606 if len(args) == 0:
1607 logger.info('\n'.join(self.history))
1608 return
1609 elif args[0] == 'clean':
1610 self.history = []
1611 logger.info('History is cleaned')
1612 return
1613 elif args[0] == '.':
1614 output_file = os.path.join(self._export_dir, 'Cards', \
1615 'proc_card_mg5.dat')
1616 output_file = open(output_file, 'w')
1617 else:
1618 output_file = open(args[0], 'w')
1619
1620
1621 text = self.get_history_header()
1622 text += ('\n'.join(self.history) + '\n')
1623
1624
1625 output_file.write(text)
1626 output_file.close()
1627
1628 if self.log:
1629 logger.info("History written to " + output_file.name)
1630
1631 - def compile(self, *args, **opts):
1635
1636 - def avoid_history_duplicate(self, line, no_break=[]):
1637 """remove all line in history (but the last) starting with line.
1638 up to the point when a line didn't start by something in no_break.
1639 (reading in reverse order)"""
1640
1641 new_history = []
1642 for i in range(1, len(self.history)+1):
1643 cur_line = self.history[-i]
1644 if i == 1:
1645 new_history.append(cur_line)
1646 elif not any((cur_line.startswith(text) for text in no_break)):
1647 to_add = self.history[:-i+1]
1648 to_add.reverse()
1649 new_history += to_add
1650 break
1651 elif cur_line.startswith(line):
1652 continue
1653 else:
1654 new_history.append(cur_line)
1655
1656 new_history.reverse()
1657 self.history[:] = new_history
1658
1659
1661
1662 if self.history:
1663 self.history.pop()
1664
1665
1666
1667 previous_store_line = self.get_stored_line()
1668
1669
1670 if isinstance(filepath, str):
1671 commandline = open(filepath).readlines()
1672 else:
1673 commandline = filepath
1674 oldinputfile = self.inputfile
1675 oldraw = self.use_rawinput
1676 self.inputfile = (l for l in commandline)
1677 self.use_rawinput = False
1678
1679
1680
1681 for line in self.inputfile:
1682
1683
1684 line = line.replace('\n', '').strip()
1685
1686 if line:
1687 self.exec_cmd(line, precmd=True)
1688 stored = self.get_stored_line()
1689 while stored:
1690 line = stored
1691 self.exec_cmd(line, precmd=True)
1692 stored = self.get_stored_line()
1693
1694
1695 if self.child:
1696 self.child.exec_cmd('quit')
1697 self.inputfile = oldinputfile
1698 self.use_rawinput = oldraw
1699
1700
1701 cmd = self
1702 while hasattr(cmd, 'mother') and cmd.mother:
1703 cmd = cmd.mother
1704 cmd.stored_line = previous_store_line
1705 return
1706
1708 """Default history header"""
1709
1710 return self.history_header
1711
1712 - def postloop(self):
1713 """ """
1714
1715 if self.use_rawinput and self.completekey:
1716 try:
1717 import readline
1718 readline.set_completer(self.old_completer)
1719 del self.old_completer
1720 except ImportError:
1721 pass
1722 except AttributeError:
1723 pass
1724
1725 args = self.split_arg(self.lastcmd)
1726 if args and args[0] in ['quit','exit']:
1727 if 'all' in args:
1728 return True
1729 if len(args) >1 and args[1].isdigit():
1730 if args[1] not in ['0', '1']:
1731 return True
1732
1733 return False
1734
1735
1736
1737
1738 @staticmethod
1745
1746 signal.signal(signal.SIGALRM, handle_alarm)
1747
1748 if fct is None:
1749 fct = six.moves.input
1750
1751 if timeout:
1752 signal.alarm(timeout)
1753 question += '[%ss to answer] ' % (timeout)
1754 try:
1755 result = fct(question)
1756 except TimeOutError:
1757 if noerror:
1758 logger.info('\nuse %s' % default)
1759 if fct_timeout:
1760 fct_timeout(True)
1761 return default
1762 else:
1763 signal.alarm(0)
1764 raise
1765 finally:
1766 signal.alarm(0)
1767 if fct_timeout:
1768 fct_timeout(False)
1769 return result
1770
1771
1772
1773
1774
1775
1776
1778 """Not in help: exit the mainloop() """
1779
1780 if self.child:
1781 self.child.exec_cmd('quit ' + line, printcmd=False)
1782 return
1783 elif self.mother:
1784 self.mother.child = None
1785 if line == 'all':
1786 self.mother.do_quit('all')
1787 pass
1788 elif line:
1789 level = int(line) - 1
1790 if level:
1791 self.mother.lastcmd = 'quit %s' % level
1792 elif self.inputfile:
1793 for line in self.inputfile:
1794 logger.warning('command not executed: %s' % line.replace('\n',''))
1795
1796 return True
1797
1798
1799 do_EOF = do_quit
1800 do_exit = do_quit
1801
1803 """Not in help: propose some usefull possible action """
1804
1805
1806 if line:
1807 return super(Cmd, self).do_help(line)
1808
1809
1810 names = self.get_names()
1811 cmds = {}
1812 names.sort()
1813
1814 prevname = ''
1815 for name in names:
1816 if name[:3] == 'do_':
1817 if name == prevname:
1818 continue
1819 prevname = name
1820 cmdname=name[3:]
1821 try:
1822 doc = getattr(self.cmd, name).__doc__
1823 except Exception:
1824 doc = None
1825 if not doc:
1826 doc = getattr(self, name).__doc__
1827 if not doc:
1828 tag = "Documented commands"
1829 elif ':' in doc:
1830 tag = doc.split(':',1)[0]
1831 else:
1832 tag = "Documented commands"
1833 if tag in cmds:
1834 cmds[tag].append(cmdname)
1835 else:
1836 cmds[tag] = [cmdname]
1837
1838 self.stdout.write("%s\n"%str(self.doc_leader))
1839 for tag in self.helporder:
1840 if tag not in cmds:
1841 continue
1842 header = "%s (type help <topic>):" % tag
1843 self.print_topics(header, cmds[tag], 15,80)
1844 for name, item in cmds.items():
1845 if name in self.helporder:
1846 continue
1847 if name == "Not in help":
1848 continue
1849 header = "%s (type help <topic>):" % name
1850 self.print_topics(header, item, 15,80)
1851
1852
1853
1854 if len(self.history) == 0:
1855 last_action_2 = last_action = 'start'
1856 else:
1857 last_action_2 = last_action = 'none'
1858
1859 pos = 0
1860 authorize = list(self.next_possibility.keys())
1861 while last_action_2 not in authorize and last_action not in authorize:
1862 pos += 1
1863 if pos > len(self.history):
1864 last_action_2 = last_action = 'start'
1865 break
1866
1867 args = self.history[-1 * pos].split()
1868 last_action = args[0]
1869 if len(args)>1:
1870 last_action_2 = '%s %s' % (last_action, args[1])
1871 else:
1872 last_action_2 = 'none'
1873
1874 logger.info('Contextual Help')
1875 logger.info('===============')
1876 if last_action_2 in authorize:
1877 options = self.next_possibility[last_action_2]
1878 elif last_action in authorize:
1879 options = self.next_possibility[last_action]
1880 else:
1881 return
1882 text = 'The following command(s) may be useful in order to continue.\n'
1883 for option in options:
1884 text+='\t %s \n' % option
1885 logger.info(text)
1886
1888 """Advanced commands: basic display"""
1889
1890 args = self.split_arg(line)
1891
1892
1893 if len(args) == 0:
1894 self.help_display()
1895 raise self.InvalidCmd('display require at least one argument')
1896
1897 if args[0] == "options":
1898 outstr = "Value of current Options:\n"
1899 for key, value in self.options.items():
1900 outstr += '%25s \t:\t%s\n' %(key,value)
1901 output.write(outstr)
1902
1903 elif args[0] == "variable":
1904 outstr = "Value of Internal Variable:\n"
1905 try:
1906 var = eval(args[1])
1907 except Exception:
1908 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
1909 else:
1910 outstr += 'GLOBAL:\n'
1911 outstr += misc.nice_representation(var, nb_space=4)
1912
1913 try:
1914 var = eval('self.%s' % args[1])
1915 except Exception:
1916 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
1917 else:
1918 outstr += 'LOCAL:\n'
1919 outstr += misc.nice_representation(var, nb_space=4)
1920 split = args[1].split('.')
1921 for i, name in enumerate(split):
1922 try:
1923 __import__('.'.join(split[:i+1]))
1924 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1])))
1925 except ImportError:
1926 try:
1927 var = eval(args[1])
1928 except Exception as error:
1929 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1]
1930 break
1931 else:
1932 outstr += 'EXTERNAL:\n'
1933 outstr += misc.nice_representation(var, nb_space=4)
1934 else:
1935 var = eval(args[1])
1936 outstr += 'EXTERNAL:\n'
1937 outstr += misc.nice_representation(var, nb_space=4)
1938
1939 pydoc.pager(outstr)
1940
1941
1942 - def do_save(self, line, check=True):
1943 """Save the configuration file"""
1944
1945 args = self.split_arg(line)
1946
1947 if check:
1948 Cmd.check_save(self, args)
1949
1950
1951 if 'HOME' in os.environ and os.environ['HOME'] and \
1952 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
1953 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
1954 if hasattr(self, 'me_dir'):
1955 basedir = self.me_dir
1956 elif not MADEVENT:
1957 basedir = MG5DIR
1958 else:
1959 basedir = os.getcwd()
1960 elif MADEVENT:
1961
1962 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']:
1963 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)):
1964 base = pjoin(self.me_dir, 'Cards', config_file)
1965 basedir = self.me_dir
1966 else:
1967 if hasattr(self, 'me_dir'):
1968 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1969 if len(args) == 0 and os.path.exists(base):
1970 self.write_configuration(base, base, self.me_dir)
1971 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1972 basedir = MG5DIR
1973
1974 if len(args) == 0:
1975 args.append(base)
1976 self.write_configuration(args[0], base, basedir, self.options)
1977
1979 """Write the configuration file"""
1980
1981
1982
1983
1984 logger.info('save configuration file to %s' % filepath)
1985 to_write = list(to_keep.keys())
1986 text = ""
1987 has_mg5_path = False
1988
1989 for line in open(basefile):
1990 if '=' in line:
1991 data, value = line.split('=',1)
1992 else:
1993 text += line
1994 continue
1995 data = data.strip()
1996 if data.startswith('#'):
1997 key = data[1:].strip()
1998 else:
1999 key = data
2000 if '#' in value:
2001 value, comment = value.split('#',1)
2002 else:
2003 comment = ''
2004 if key in to_keep:
2005 value = str(to_keep[key])
2006 else:
2007 text += line
2008 continue
2009 if key == 'mg5_path':
2010 has_mg5_path = True
2011 try:
2012 to_write.remove(key)
2013 except Exception:
2014 pass
2015 if '_path' in key:
2016
2017
2018 if not os.path.isabs(value):
2019 value = os.path.realpath(os.path.join(basedir, value))
2020 text += '%s = %s # %s \n' % (key, value, comment)
2021 for key in to_write:
2022 if key in to_keep:
2023 text += '%s = %s \n' % (key, to_keep[key])
2024
2025 if not MADEVENT and not has_mg5_path:
2026 text += """\n# MG5 MAIN DIRECTORY\n"""
2027 text += "mg5_path = %s\n" % MG5DIR
2028
2029 writer = open(filepath,'w')
2030 writer.write(text)
2031 writer.close()
2032
2037 """CMD command with shell activate"""
2038
2039
2041 "Run a shell command"
2042
2043 if not line.strip():
2044 self.help_shell()
2045 else:
2046 logging.info("running shell command: " + line)
2047 subprocess.call(line, shell=True)
2048
2063
2065 """help for the shell"""
2066 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')
2067 logger.info("syntax: shell CMD (or ! CMD)",'$MG:BOLD')
2068
2072
2076 """ a class for answering a question with the path autocompletion"""
2077
2078 allowpath = False
2080 """Initializing before starting the main loop"""
2081 self.prompt = '>'
2082 self.value = None
2083 BasicCmd.preloop(self)
2084
2085 @property
2088
2089 - def __init__(self, question, allow_arg=[], default=None,
2090 mother_interface=None, *arg, **opt):
2091
2092 self.question = question
2093 self.wrong_answer = 0
2094 self.allow_arg = [str(a) for a in allow_arg]
2095 self.history_header = ''
2096 self.default_value = str(default)
2097 self.mother_interface = mother_interface
2098
2099 if 'case' in opt:
2100 self.casesensitive = opt['case']
2101 del opt['case']
2102 elif 'casesensitive' in opt:
2103 self.casesensitive = opt['casesensitive']
2104 del opt['casesensitive']
2105 else:
2106 self.casesensistive = True
2107 super(SmartQuestion, self).__init__(*arg, **opt)
2108
2109 - def __call__(self, question, reprint_opt=True, **opts):
2110
2111 self.question = question
2112 for key,value in opts:
2113 setattr(self, key, value)
2114 if reprint_opt:
2115 print(question)
2116 logger_tuto.info("Need help here? type 'help'", '$MG:BOLD')
2117 logger_plugin.info("Need help here? type 'help'" , '$MG:BOLD')
2118 return self.cmdloop()
2119
2120
2122 prev_timer = signal.alarm(0)
2123 if prev_timer:
2124 nb_back = len(line)
2125 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2126 self.stdout.write(line)
2127 self.stdout.flush()
2128 try:
2129 out = {}
2130 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2131 out[' Recognized command'] = super(SmartQuestion, self).completenames(text,line, *ignored)
2132
2133 return self.deal_multiple_categories(out)
2134 except Exception as error:
2135 print(error)
2136
2137 completedefault = completenames
2138
2140
2141
2142 return dir(self)
2143
2144 - def onecmd(self, line, **opt):
2145 """catch all error and stop properly command accordingly
2146 Interpret the argument as though it had been typed in response
2147 to the prompt.
2148
2149 The return value is a flag indicating whether interpretation of
2150 commands by the interpreter should stop.
2151
2152 This allow to pass extra argument for internal call.
2153 """
2154 try:
2155 if '~/' in line and 'HOME' in os.environ:
2156 line = line.replace('~/', '%s/' % os.environ['HOME'])
2157 line = os.path.expandvars(line)
2158 cmd, arg, line = self.parseline(line)
2159 if not line:
2160 return self.emptyline()
2161 if cmd is None:
2162 return self.default(line)
2163 self.lastcmd = line
2164 if cmd == '':
2165 return self.default(line)
2166 else:
2167 try:
2168 func = getattr(self, 'do_' + cmd)
2169 except AttributeError:
2170 return self.default(line)
2171 return func(arg, **opt)
2172 except Exception as error:
2173 logger.warning(error)
2174 if __debug__:
2175 raise
2176
2177 - def reask(self, reprint_opt=True):
2178 pat = re.compile('\[(\d*)s to answer\]')
2179 prev_timer = signal.alarm(0)
2180
2181 if prev_timer:
2182 if pat.search(self.question):
2183 timeout = int(pat.search(self.question).groups()[0])
2184 signal.alarm(timeout)
2185 if reprint_opt:
2186 if not prev_timer:
2187 self.question = pat.sub('',self.question)
2188 print(self.question)
2189
2190 if self.mother_interface:
2191 answer = self.mother_interface.check_answer_in_input_file(self, 'EOF',
2192 path=self.allowpath)
2193 if answer:
2194 stop = self.default(answer)
2195 self.postcmd(stop, answer)
2196 return False
2197
2198 return False
2199
2201
2202 text=line
2203 out ={}
2204 out['Options'] = Cmd.list_completion(text, self.allow_arg)
2205 out['command'] = BasicCmd.completenames(self, text)
2206
2207 if not text:
2208 if out['Options']:
2209 logger.info( "Here is the list of all valid options:", '$MG:BOLD')
2210 logger.info( " "+ "\n ".join(out['Options']))
2211 if out['command']:
2212 logger.info( "Here is the list of command available:", '$MG:BOLD')
2213 logger.info( " "+ "\n ".join(out['command']))
2214 else:
2215 if out['Options']:
2216 logger.info( "Here is the list of all valid options starting with \'%s\'" % text, '$MG:BOLD')
2217 logger.info( " "+ "\n ".join(out['Options']))
2218 if out['command']:
2219 logger.info( "Here is the list of command available starting with \'%s\':" % text, '$MG:BOLD')
2220 logger.info( " "+ "\n ".join(out['command']))
2221 elif not out['Options']:
2222 logger.info( "No possibility starting with \'%s\'" % text, '$MG:BOLD')
2223 logger.info( "You can type help XXX, to see all command starting with XXX", '$MG:BOLD')
2227
2229 """Default action if line is not recognized"""
2230
2231 if line.strip() == '' and self.default_value is not None:
2232 self.value = self.default_value
2233 else:
2234 self.value = line
2235
2237 """If empty line, return default"""
2238
2239 if self.default_value is not None:
2240 self.value = self.default_value
2241
2242
2243 - def postcmd(self, stop, line):
2244
2245 try:
2246 if self.value in self.allow_arg:
2247 return True
2248 elif str(self.value) == 'EOF':
2249 self.value = self.default_value
2250 return True
2251 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2252 return self.reask()
2253 elif self.value in ['repeat', 'reask']:
2254 return self.reask()
2255 elif len(self.allow_arg)==0:
2256 return True
2257 elif ' ' in line.strip() and '=' in self.value:
2258 line,n = re.subn(r'\s*=\s*', '=', line)
2259 if n:
2260 self.default(line)
2261 return self.postcmd(stop, line)
2262 if not self.casesensitive:
2263 for ans in self.allow_arg:
2264 if ans.lower() == self.value.lower():
2265 self.value = ans
2266 return True
2267 break
2268 else:
2269 raise Exception
2270
2271
2272 else:
2273 raise Exception
2274 except Exception as error:
2275 if self.wrong_answer < 100:
2276 self.wrong_answer += 1
2277 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
2278 % (self.value,','.join(self.allow_arg)))
2279 logger.warning('please retry')
2280 return False
2281 else:
2282 self.value = self.default_value
2283 return True
2284
2288
2294
2299 """ a class for answering a question with the path autocompletion"""
2300
2301 completion_prefix=''
2302 allowpath=True
2303
2304 - def completenames(self, text, line, begidx, endidx, formatting=True):
2305 prev_timer = signal.alarm(0)
2306 if prev_timer:
2307 nb_back = len(line)
2308 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2309 self.stdout.write(line)
2310 self.stdout.flush()
2311
2312 try:
2313 out = {}
2314 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2315 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
2316 out[' Recognized command'] = BasicCmd.completenames(self, text, line, begidx, endidx)
2317
2318 return self.deal_multiple_categories(out, formatting)
2319 except Exception as error:
2320 print(error)
2321
2327
2329 prev_timer = signal.alarm(0)
2330 if prev_timer:
2331 nb_back = len(line)
2332 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2333 self.stdout.write(line)
2334 self.stdout.flush()
2335 try:
2336 args = Cmd.split_arg(line[0:begidx])
2337 except Exception as error:
2338 print(error)
2339
2340
2341 if args[-1].endswith(os.path.sep):
2342
2343 return Cmd.path_completion(text,
2344 os.path.join('.',*[a for a in args \
2345 if a.endswith(os.path.sep)]),
2346 begidx, endidx)
2347 return self.completenames(text, line, begidx, endidx)
2348
2349
2350 - def postcmd(self, stop, line):
2351 try:
2352 if self.value in self.allow_arg:
2353 return True
2354 elif self.value and os.path.isfile(self.value):
2355 return os.path.relpath(self.value)
2356 elif self.value and str(self.value) == 'EOF':
2357 self.value = self.default_value
2358 return True
2359 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2360
2361 reprint_opt = True
2362 elif self.value in ['repeat', 'reask']:
2363 reprint_opt = True
2364 else:
2365 raise Exception
2366 except Exception as error:
2367 print("""not valid argument. Valid argument are file path or value in (%s).""" \
2368 % ','.join(self.allow_arg))
2369 print('please retry')
2370 reprint_opt = False
2371
2372 if line != 'EOF':
2373 return self.reask(reprint_opt)
2374
2381
2385 """A class for asking a question on which program to run.
2386 This is the abstract class
2387
2388 Behavior for each switch can be customize via:
2389 set_default_XXXX() -> set default value
2390 This is super-seeded by self.default_switch if that attribute is defined (and has a key for XXXX)
2391 get_allowed_XXXX() -> return list of possible value
2392 check_value_XXXX(value) -> return True/False if the user can set such value
2393 switch_off_XXXXX() -> set it off (called for special mode)
2394 color_for_XXXX(value) -> return the representation on the screen for value
2395 get_cardcmd_for_XXXX(value)> return the command to run to customize the cards to
2396 match the status
2397 print_options_XXXX() -> return the text to disply below "other options"
2398 default is other possible value (ordered correctly)
2399
2400 consistency_XX_YY(val_XX, val_YY)
2401 -> XX is the new key set by the user to a new value val_XX
2402 -> YY is another key set by the user.
2403 -> return value should be None or "replace_YY"
2404
2405 consistency_XX(val_XX):
2406 check the consistency of the other switch given the new status of this one.
2407 return a dict {key:replaced_value} or {} if nothing to do
2408
2409 user typing "NAME" will result to a call to self.ans_NAME(None)
2410 user typing "NAME=XX" will result to a call to self.ans_NAME('XX')
2411
2412 Note on case sensitivity:
2413 -------------------------
2414 the XXX is displayed with the case in self.to_control
2415 but ALL functions should use the lower case version.
2416 for key associated to get_allowed_keys(),
2417 if (user) value not in that list.
2418 -> try to find the first entry matching up to the case
2419 for ans_XXX, set the value to lower case, but if case_XXX is set to True
2420 """
2421
2422 case_sensitive = False
2423 quit_on = ['0','done', 'EOF','','auto']
2424
2425 - def __init__(self, to_control, motherinstance, *args, **opts):
2426 """to_control is a list of ('KEY': 'Choose the shower/hadronization program')
2427 """
2428
2429 self.to_control = to_control
2430 self.mother_interface = motherinstance
2431 self.inconsistent_keys = {}
2432
2433
2434 self.inconsistent_details = {}
2435 self.last_changed = []
2436
2437
2438 self.switch = {}
2439 for key, _ in to_control:
2440 self.switch[key.lower()] = 'temporary'
2441
2442 self.set_default_switch()
2443 question = self.create_question()
2444
2445
2446 allowed_args = [ repr(i)+';' for i in range(1, 1+len(self.to_control))]
2447 for key in self.switch:
2448 allowed_args += ['%s=%s;' % (key,s) for s in self.get_allowed(key)]
2449
2450 allowed_args += [key[4:]+';' for key in dir(self) if key.startswith('ans_')]
2451 allowed_args += [arg[:-1] for arg in allowed_args if arg[-1] == ';']
2452 if 'allow_arg' in opts:
2453 allowed_args += opts['allow_arg']
2454 del opts['allow_arg']
2455
2456 allowed_args +=["0", "done"]
2457 SmartQuestion.__init__(self, question, allowed_args, *args, **opts)
2458 self.options = self.mother_interface.options
2459
2486
2487
2488
2489
2490
2492
2493 for key,_ in self.to_control:
2494 key = key.lower()
2495 if hasattr(self, 'default_switch') and key in self.default_switch:
2496 self.switch[key] = self.default_switch[key]
2497 continue
2498 if hasattr(self, 'set_default_%s' % key):
2499 getattr(self, 'set_default_%s' % key)()
2500 else:
2501 self.default_switch_for(key)
2502
2504 """use this if they are no dedicated function for such key"""
2505
2506 if hasattr(self, 'get_allowed_%s' % key):
2507 return getattr(self, 'get_allowed_%s' % key)()[0]
2508 else:
2509 self.switch[key] = 'OFF'
2510
2512 """set all valid parameter to OFF --call before special keyword--
2513 """
2514
2515 for key in self.switch:
2516 if hasattr(self, 'switch_off_%s' % key):
2517 getattr(self, 'switch_off_%s' % key)()
2518 elif self.check_value(key, self.switch[key]):
2519 self.switch[key] = 'OFF'
2520 self.inconsistent_details = {}
2521 self.inconsistent_keys = {}
2522
2523
2525 """return True/False if the value is a correct value to be set by the USER.
2526 other value than those can be set by the system --like-- Not available.
2527 This does not check the full consistency of the switch
2528 """
2529
2530 if hasattr(self, 'check_value_%s' % key):
2531 return getattr(self, 'check_value_%s' % key)(value)
2532 elif value in self.get_allowed(key):
2533 return True
2534 else:
2535 return False
2536
2537
2539 """ return the list of command that need to be run to have a consistent
2540 set of cards with the switch value choosen """
2541
2542 switch = self.answer
2543 cmd= []
2544 for key in self.switch:
2545 if hasattr(self, 'get_cardcmd_for_%s' % key):
2546 cmd += getattr(self, 'get_cardcmd_for_%s' % key)(switch[key])
2547 return cmd
2548
2549
2551 """return the list of possible value for key"""
2552
2553 if hasattr(self, 'get_allowed_%s' % key):
2554 return getattr(self, 'get_allowed_%s' % key)()
2555 else:
2556 return ['ON', 'OFF']
2557
2558 - def default(self, line, raise_error=False):
2559 """Default action if line is not recognized"""
2560
2561 line=line.strip().replace('@', '__at__')
2562 if ';' in line:
2563 for l in line.split(';'):
2564 if l:
2565 out = self.default(l)
2566 return out
2567
2568 if '=' in line:
2569 base, value = line.split('=',1)
2570 base = base.strip()
2571 value = value.strip()
2572
2573 if base.isdigit() :
2574 try:
2575 base = self.to_control[int(base)-1][0]
2576 except:
2577 pass
2578 elif ' ' in line:
2579 base, value = line.split(' ', 1)
2580 elif hasattr(self, 'ans_%s' % line.lower()):
2581 base, value = line.lower(), None
2582 elif line.isdigit() and line in [repr(i) for i in range(1, len(self.to_control)+1)]:
2583
2584 base = self.to_control[int(line)-1][0].lower()
2585 return self.default(base)
2586 elif line.lower() in self.switch:
2587
2588 base = line.lower()
2589 try:
2590 cur = self.get_allowed(base).index(self.switch[base])
2591 except:
2592 if self.get_allowed(base):
2593 value = self.get_allowed(base)[0]
2594 else:
2595 logger.warning('Can not switch "%s" to another value via number', base)
2596 self.value='reask'
2597 return
2598 else:
2599 try:
2600 value = self.get_allowed(base)[cur+1]
2601 except IndexError:
2602 value = self.get_allowed(base)[0]
2603 if value == "OFF" and cur == 0:
2604 logger.warning("Invalid action: %s" % self.print_options(base))
2605 elif cur == 0:
2606 logger.warning("Can not change value for this parameter")
2607
2608
2609 elif line in ['', 'done', 'EOF', 'eof','0']:
2610 super(ControlSwitch, self).default(line)
2611 return self.answer
2612 elif line in 'auto':
2613 self.switch['dynamical'] = True
2614 return super(ControlSwitch, self).default(line)
2615 elif line.startswith('set ') and not hasattr(self.__class__, 'do_set'):
2616 raise NotValidInput('unknow command: %s. Did you mean \"%s\"' % (line, line[4:]))
2617 elif raise_error:
2618 raise NotValidInput('unknow command: %s' % line)
2619 else:
2620 logger.warning('unknow command: %s' % line)
2621 self.value = 'reask'
2622 return
2623
2624 self.value = 'reask'
2625 base = base.lower()
2626 if hasattr(self, 'ans_%s' % base):
2627 if value and not self.is_case_sensitive(base):
2628 value = value.lower()
2629 getattr(self, 'ans_%s' % base)(value)
2630 elif base in self.switch:
2631 self.set_switch(base, value)
2632 elif line.startswith('set ') and not hasattr(self.__class__, 'do_set'):
2633 raise NotValidInput('Not valid command: %s. Did you mean \"%s\"' % (line, line[4:]))
2634 elif raise_error:
2635 raise NotValidInput('Not valid command: %s' % line)
2636 else:
2637 logger.warning('Not valid command: %s' % line)
2638
2640 """check if a key is case sensitive"""
2641
2642 case = self.case_sensitive
2643 if hasattr(self, 'case_%s' % key):
2644 case = getattr(self, 'case_%s' % key)
2645 return case
2646
2647 - def onecmd(self, line, **opt):
2652
2653 @property
2655
2656
2657 for key,_ in self.to_control:
2658 if not self.check_value(key, self.switch[key]):
2659 self.switch[key] = 'OFF'
2660
2661 if not self.inconsistent_keys:
2662 return self.switch
2663 else:
2664 out = dict(self.switch)
2665 out.update(self.inconsistent_keys)
2666 return out
2667
2668 - def postcmd(self, stop, line):
2669
2670
2671
2672 try:
2673 out = super(ControlSwitch,self).postcmd(stop, line)
2674 except AttributeError:
2675 pass
2676 if out:
2677 return out
2678
2679 line = line.strip()
2680 if ';' in line:
2681 line= [l for l in line.split(';') if l][-1]
2682 if line in self.quit_on or self.value in self.quit_on:
2683 return True
2684 if self.value != 'reask':
2685 self.create_question()
2686 return self.reask(True)
2687 return
2688
2690 """change a switch to a given value"""
2691
2692 assert key in self.switch
2693
2694 if hasattr(self, 'ans_%s' % key):
2695 if not self.is_case_sensitive(key):
2696 value = value.lower()
2697 return getattr(self, 'ans_%s' % key)(value)
2698
2699 if not self.is_case_sensitive(key) and value not in self.get_allowed(key):
2700 lower = [t.lower() for t in self.get_allowed(key)]
2701 try:
2702 ind = lower.index(value.lower())
2703 except ValueError:
2704 pass
2705 else:
2706 value = self.get_allowed(key)[ind]
2707
2708 check = self.check_value(key, value)
2709 if not check:
2710 logger.warning('"%s" not valid option for "%s"', value, key)
2711 return
2712 if isinstance(check, str):
2713 value = check
2714
2715 self.switch[key] = value
2716
2717 if user:
2718 self.check_consistency(key, value)
2719
2721
2722 if not keys:
2723 self.inconsistent_keys = {}
2724 self.inconsistent_details = {}
2725 elif isinstance(keys, list):
2726 for key in keys:
2727 if key in self.inconsistent_keys:
2728 del self.inconsistent_keys[keys]
2729 del self.inconsistent_details[keys]
2730 else:
2731 if keys in self.inconsistent_keys:
2732 del self.inconsistent_keys[keys]
2733 del self.inconsistent_details[keys]
2734
2736 """check the consistency of the new flag with the old ones"""
2737
2738
2739 if key in self.last_changed:
2740 self.last_changed.remove(key)
2741 self.last_changed.append(key)
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755 if hasattr(self, 'consistency_%s' % key):
2756 rules = dict([(key2, None) for key2 in self.switch])
2757 rules.update(getattr(self, 'consistency_%s' % key)(value, self.switch))
2758 else:
2759 rules = {}
2760 for key2,value2 in self.switch.items():
2761 if hasattr(self, 'consistency_%s_%s' % (key,key2)):
2762 rules[key2] = getattr(self, 'consistency_%s_%s' % (key,key2))(value, value2)
2763
2764
2765 if rules[key2] is not None and not self.check_value(key2, rules[key2]):
2766 if rules[key2] != 'OFF':
2767 logger.debug('consistency_%s_%s returns invalid output. Assume no conflict')
2768 rules[key2] = None
2769 else:
2770 rules[key2] = None
2771
2772
2773
2774
2775
2776 self.remove_inconsistency(key)
2777
2778 for key2 in self.switch:
2779 if rules[key2]:
2780 info = {'orig_value': self.switch[key2],
2781 'changed_key': key,
2782 'new_changed_key_val': value,
2783 'replacement': rules[key2]}
2784 if key2 in self.inconsistent_details:
2785 self.inconsistent_details[key2].append(info)
2786 else:
2787 self.inconsistent_details[key2] = [info]
2788
2789 if not self.inconsistent_details:
2790 return
2791
2792
2793 for key2 in dict(self.inconsistent_details):
2794 for conflict in list(self.inconsistent_details[key2]):
2795 keep_conflict = True
2796
2797 if conflict['orig_value'] != self.switch[key2]:
2798 keep_conflict = False
2799
2800 if self.switch[conflict['changed_key']] != conflict['new_changed_key_val']:
2801 keep_conflict = False
2802 if not keep_conflict:
2803 self.inconsistent_details[key2].remove(conflict)
2804 if not self.inconsistent_details[key2]:
2805 del self.inconsistent_details[key2]
2806
2807
2808
2809
2810 tmp_switch = dict(self.switch)
2811
2812
2813 to_check = [(c['changed_key'], c['new_changed_key_val']) \
2814 for k in self.inconsistent_details.values() for c in k
2815 if c['changed_key'] != key]
2816
2817 to_check.sort(key=lambda x: self.last_changed.index(x[0]))
2818
2819
2820 to_check = [(key, value)] + to_check
2821
2822 i = 0
2823 while len(to_check) and i < 50:
2824
2825
2826 i +=1
2827 key2, value2 = to_check.pop(0)
2828 if hasattr(self, 'consistency_%s' % key2):
2829 rules2 = dict([(key2, None) for key2 in self.switch])
2830 rules2.update(getattr(self, 'consistency_%s' % key2)(value, tmp_switch))
2831 else:
2832 rules = {}
2833 for key3,value3 in self.switch.items():
2834 if hasattr(self, 'consistency_%s_%s' % (key2,key3)):
2835 rules[key3] = getattr(self, 'consistency_%s_%s' % (key2,key3))(value2, value3)
2836 else:
2837 rules[key3] = None
2838
2839 for key, replacement in rules.items():
2840 if replacement:
2841 tmp_switch[key] = replacement
2842 to_check.append((key, replacement))
2843
2844
2845
2846 pos = {}
2847 for i, (key,value) in enumerate(to_check):
2848 pos[key] = i
2849 to_check_new = []
2850 for i, (key,value) in enumerate(to_check):
2851 if pos[key] == i:
2852 to_check_new.append((key,value))
2853 to_check = to_check_new
2854 if i>=50:
2855 logger.critical('Failed to find a consistent set of switch values.')
2856
2857
2858
2859 self.inconsistent_keys = {}
2860 for key2, value2 in tmp_switch.items():
2861 if value2 != self.switch[key2]:
2862
2863 if value2 == 'OFF' and not self.check_value(key2, 'OFF'):
2864 continue
2865 self.inconsistent_keys[key2] = value2
2866
2867
2868
2869
2870 green = '\x1b[32m%s\x1b[0m'
2871 yellow = '\x1b[33m%s\x1b[0m'
2872 red = '\x1b[31m%s\x1b[0m'
2873 bold = '\x1b[01m%s\x1b[0m'
2875
2876 if consistency and key in self.inconsistent_keys:
2877 return self.color_for_value(key, self.inconsistent_keys[key], consistency=False) +\
2878 u' \u21d0 '+ self.yellow % switch_value
2879
2880 if self.check_value(key, switch_value):
2881 if hasattr(self, 'color_for_%s' % key):
2882 return getattr(self, 'color_for_%s' % key)(switch_value)
2883 if switch_value in ['OFF']:
2884
2885 return self.red % switch_value
2886 else:
2887 return self.green % switch_value
2888 else:
2889 if ' ' in switch_value:
2890 return self.bold % switch_value
2891 else:
2892 return self.red % switch_value
2893
2895
2896 if hasattr(self, 'print_options_%s' % key) and not keep_default:
2897 return getattr(self, 'print_options_%s' % key)()
2898
2899
2900 try:
2901 ind = self.get_allowed(key).index(self.switch[key])
2902 except Exception as err:
2903 options = self.get_allowed(key)
2904 else:
2905 options = self.get_allowed(key)[ind:]+ self.get_allowed(key)[:ind]
2906
2907 info = '|'.join([v for v in options if v != self.switch[key]])
2908 if info == '':
2909 info = 'Please install module'
2910 return info
2911
2912 - def do_help(self, line, list_command=False):
2913 """dedicated help for the control switch"""
2914
2915 if line:
2916 return self.print_help_for_switch(line)
2917
2918
2919 logger.info(" ")
2920 logger.info(" In order to change a switch you can:")
2921 logger.info(" - type 'NAME = VALUE' to set the switch NAME to a given value.")
2922 logger.info(" - type 'ID = VALUE' to set the switch correspond to the line ID to a given value.")
2923 logger.info(" - type 'ID' where ID is the value of the line to pass from one value to the next.")
2924 logger.info(" - type 'NAME' to set the switch NAME to the next value.")
2925 logger.info("")
2926 logger.info(" You can type 'help NAME' for more help on a given switch")
2927 logger.info("")
2928 logger.info(" Special keyword:", '$MG:BOLD')
2929 logger.info(" %s" % '\t'.join([p[4:] for p in dir(self) if p.startswith('ans_')]) )
2930 logger.info(" type 'help XXX' for more information")
2931 if list_command:
2932 super(ControlSwitch, self).do_help(line)
2933
2934
2936 """ """
2937
2938 arg = line.split()[0]
2939
2940 if hasattr(self, 'help_%s' % arg):
2941 return getattr(self, 'help_%s' % arg)('')
2942
2943 if hasattr(self, 'ans_%s' % arg):
2944 return getattr(self, 'help_%s' % arg).__doc__
2945
2946 if arg in self.switch:
2947 logger.info(" information for switch %s: ", arg, '$MG:BOLD')
2948 logger.info(" allowed value:")
2949 logger.info(" %s", '\t'.join(self.get_allowed(arg)))
2950 if hasattr(self, 'help_text_%s' % arg):
2951 logger.info("")
2952 for line in getattr(self, 'help_text_%s' % arg):
2953 logger.info(line)
2954
2955
2956
2957
3129
3131 """ create the question with correct formatting"""
3132
3133
3134
3135 try:
3136 nb_rows, nb_col = os.popen('stty size', 'r').read().split()
3137 nb_rows, nb_col = int(nb_rows), int(nb_col)
3138 except Exception as error:
3139 nb_rows, nb_col = 20, 80
3140
3141
3142 max_len_description = 0
3143 max_len_switch = 0
3144 max_len_name = 0
3145 max_len_add_info = 0
3146 max_len_potential_switch = 0
3147 max_nb_key = 1 + int(math.log10(len(self.to_control)))
3148
3149 for key, descrip in self.to_control:
3150 if len(descrip) > max_len_description: max_len_description = len(descrip)
3151 if len(key) > max_len_name: max_len_name = len(key)
3152 if key in self.inconsistent_keys:
3153 to_display = '%s < %s' % (self.switch[key], self.inconsistent_keys[key])
3154 else:
3155 to_display = self.switch[key]
3156 if len(to_display) > max_len_switch: max_len_switch=len(to_display)
3157
3158 info = self.print_options(key)
3159 if len(info)> max_len_add_info: max_len_add_info = len(info)
3160
3161 if self.get_allowed(key):
3162 max_k = max(len(k) for k in self.get_allowed(key))
3163 else:
3164 max_k = 0
3165 if max_k > max_len_potential_switch: max_len_potential_switch = max_k
3166
3167 upper_line, lower_line, f1, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3168 max_len_name, max_len_add_info,
3169 max_len_potential_switch, max_nb_key)
3170
3171 text = \
3172 ["The following switches determine which programs are run:",
3173 upper_line
3174 ]
3175
3176
3177
3178 for i,(key, descrip) in enumerate(self.to_control):
3179
3180
3181
3182 data_to_format = {'nb': i+1,
3183 'descrip': descrip,
3184 'name': key,
3185 'switch': self.color_for_value(key,self.switch[key]),
3186 'add_info': self.print_options(key),
3187 'switch_nc': self.switch[key],
3188 'strike_switch': u'\u0336'.join(' %s ' %self.switch[key].upper()) + u'\u0336',
3189 }
3190 if key in self.inconsistent_keys:
3191
3192 _,_,_, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3193 max_len_name, max_len_add_info,
3194 max_len_potential_switch, max_nb_key,
3195 key=key)
3196
3197 data_to_format['conflict_switch_nc'] = self.inconsistent_keys[key]
3198 data_to_format['conflict_switch'] = self.color_for_value(key,self.inconsistent_keys[key], consistency=False)
3199 text.append(f2 % data_to_format)
3200 else:
3201 text.append(f1 % data_to_format)
3202
3203
3204 text.append(lower_line)
3205
3206
3207 example = None
3208 for key in self.switch:
3209 if len(self.get_allowed(key)) > 1:
3210 for val in self.get_allowed(key):
3211 if val != self.switch[key]:
3212 example = (key, val)
3213 break
3214 else:
3215 continue
3216 break
3217
3218 if not example:
3219 example = ('KEY', 'VALUE')
3220
3221 if help_text:
3222 text += \
3223 ["Either type the switch number (1 to %s) to change its setting," % len(self.to_control),
3224 "Set any switch explicitly (e.g. type '%s=%s' at the prompt)" % example,
3225 "Type 'help' for the list of all valid option",
3226 "Type '0', 'auto', 'done' or just press enter when you are done."]
3227
3228
3229 if len(text) > nb_rows:
3230
3231 to_remove = [ -2,
3232 -5,
3233 -4,
3234 -3,
3235 -1,
3236 ]
3237 to_remove = to_remove[:min(len(to_remove), len(text)-nb_rows)]
3238 text = [t for i,t in enumerate(text) if i-len(text) not in to_remove]
3239
3240 self.question = "\n".join(text)
3241 return self.question
3242
3243
3244
3245
3246
3247 -class CmdFile(file):
3248 """ a class for command input file -in order to debug cmd \n problem"""
3249
3256
3258 """readline method treating correctly a line whithout \n at the end
3259 (add it)
3260 """
3261 if self.lines:
3262 line = self.lines.pop(0)
3263 else:
3264 return ''
3265
3266 if line.endswith('\n'):
3267 return line
3268 else:
3269 return line + '\n'
3270
3273
3276