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):
1632 """ """
1633 import multiprocessing
1634 if not self.options['nb_core'] or self.options['nb_core'] == 'None':
1635 self.options['nb_core'] = multiprocessing.cpu_count()
1636 return misc.compile(nb_core=self.options['nb_core'], *args, **opts)
1637
1638 - def avoid_history_duplicate(self, line, no_break=[]):
1639 """remove all line in history (but the last) starting with line.
1640 up to the point when a line didn't start by something in no_break.
1641 (reading in reverse order)"""
1642
1643 new_history = []
1644 for i in range(1, len(self.history)+1):
1645 cur_line = self.history[-i]
1646 if i == 1:
1647 new_history.append(cur_line)
1648 elif not any((cur_line.startswith(text) for text in no_break)):
1649 to_add = self.history[:-i+1]
1650 to_add.reverse()
1651 new_history += to_add
1652 break
1653 elif cur_line.startswith(line):
1654 continue
1655 else:
1656 new_history.append(cur_line)
1657
1658 new_history.reverse()
1659 self.history[:] = new_history
1660
1661
1663
1664 if self.history:
1665 self.history.pop()
1666
1667
1668
1669 previous_store_line = self.get_stored_line()
1670
1671
1672 if isinstance(filepath, str):
1673 commandline = open(filepath).readlines()
1674 else:
1675 commandline = filepath
1676 oldinputfile = self.inputfile
1677 oldraw = self.use_rawinput
1678 self.inputfile = (l for l in commandline)
1679 self.use_rawinput = False
1680
1681
1682
1683 for line in self.inputfile:
1684
1685
1686 line = line.replace('\n', '').strip()
1687
1688 if line:
1689 self.exec_cmd(line, precmd=True)
1690 stored = self.get_stored_line()
1691 while stored:
1692 line = stored
1693 self.exec_cmd(line, precmd=True)
1694 stored = self.get_stored_line()
1695
1696
1697 if self.child:
1698 self.child.exec_cmd('quit')
1699 self.inputfile = oldinputfile
1700 self.use_rawinput = oldraw
1701
1702
1703 cmd = self
1704 while hasattr(cmd, 'mother') and cmd.mother:
1705 cmd = cmd.mother
1706 cmd.stored_line = previous_store_line
1707 return
1708
1710 """Default history header"""
1711
1712 return self.history_header
1713
1714 - def postloop(self):
1715 """ """
1716
1717 if self.use_rawinput and self.completekey:
1718 try:
1719 import readline
1720 readline.set_completer(self.old_completer)
1721 del self.old_completer
1722 except ImportError:
1723 pass
1724 except AttributeError:
1725 pass
1726
1727 args = self.split_arg(self.lastcmd)
1728 if args and args[0] in ['quit','exit']:
1729 if 'all' in args:
1730 return True
1731 if len(args) >1 and args[1].isdigit():
1732 if args[1] not in ['0', '1']:
1733 return True
1734
1735 return False
1736
1737
1738
1739
1740 @staticmethod
1747
1748 signal.signal(signal.SIGALRM, handle_alarm)
1749
1750 if fct is None:
1751 fct = six.moves.input
1752
1753 if timeout:
1754 signal.alarm(timeout)
1755 question += '[%ss to answer] ' % (timeout)
1756 try:
1757 result = fct(question)
1758 except TimeOutError:
1759 if noerror:
1760 logger.info('\nuse %s' % default)
1761 if fct_timeout:
1762 fct_timeout(True)
1763 return default
1764 else:
1765 signal.alarm(0)
1766 raise
1767 finally:
1768 signal.alarm(0)
1769 if fct_timeout:
1770 fct_timeout(False)
1771 return result
1772
1773
1774
1775
1776
1777
1778
1780 """Not in help: exit the mainloop() """
1781
1782 if self.child:
1783 self.child.exec_cmd('quit ' + line, printcmd=False)
1784 return
1785 elif self.mother:
1786 self.mother.child = None
1787 if line == 'all':
1788 self.mother.do_quit('all')
1789 pass
1790 elif line:
1791 level = int(line) - 1
1792 if level:
1793 self.mother.lastcmd = 'quit %s' % level
1794 elif self.inputfile:
1795 for line in self.inputfile:
1796 logger.warning('command not executed: %s' % line.replace('\n',''))
1797
1798 return True
1799
1800
1801 do_EOF = do_quit
1802 do_exit = do_quit
1803
1805 """Not in help: propose some usefull possible action """
1806
1807
1808 if line:
1809 return super(Cmd, self).do_help(line)
1810
1811
1812 names = self.get_names()
1813 cmds = {}
1814 names.sort()
1815
1816 prevname = ''
1817 for name in names:
1818 if name[:3] == 'do_':
1819 if name == prevname:
1820 continue
1821 prevname = name
1822 cmdname=name[3:]
1823 try:
1824 doc = getattr(self.cmd, name).__doc__
1825 except Exception:
1826 doc = None
1827 if not doc:
1828 doc = getattr(self, name).__doc__
1829 if not doc:
1830 tag = "Documented commands"
1831 elif ':' in doc:
1832 tag = doc.split(':',1)[0]
1833 else:
1834 tag = "Documented commands"
1835 if tag in cmds:
1836 cmds[tag].append(cmdname)
1837 else:
1838 cmds[tag] = [cmdname]
1839
1840 self.stdout.write("%s\n"%str(self.doc_leader))
1841 for tag in self.helporder:
1842 if tag not in cmds:
1843 continue
1844 header = "%s (type help <topic>):" % tag
1845 self.print_topics(header, cmds[tag], 15,80)
1846 for name, item in cmds.items():
1847 if name in self.helporder:
1848 continue
1849 if name == "Not in help":
1850 continue
1851 header = "%s (type help <topic>):" % name
1852 self.print_topics(header, item, 15,80)
1853
1854
1855
1856 if len(self.history) == 0:
1857 last_action_2 = last_action = 'start'
1858 else:
1859 last_action_2 = last_action = 'none'
1860
1861 pos = 0
1862 authorize = list(self.next_possibility.keys())
1863 while last_action_2 not in authorize and last_action not in authorize:
1864 pos += 1
1865 if pos > len(self.history):
1866 last_action_2 = last_action = 'start'
1867 break
1868
1869 args = self.history[-1 * pos].split()
1870 last_action = args[0]
1871 if len(args)>1:
1872 last_action_2 = '%s %s' % (last_action, args[1])
1873 else:
1874 last_action_2 = 'none'
1875
1876 logger.info('Contextual Help')
1877 logger.info('===============')
1878 if last_action_2 in authorize:
1879 options = self.next_possibility[last_action_2]
1880 elif last_action in authorize:
1881 options = self.next_possibility[last_action]
1882 else:
1883 return
1884 text = 'The following command(s) may be useful in order to continue.\n'
1885 for option in options:
1886 text+='\t %s \n' % option
1887 logger.info(text)
1888
1890 """Advanced commands: basic display"""
1891
1892 args = self.split_arg(line)
1893
1894
1895 if len(args) == 0:
1896 self.help_display()
1897 raise self.InvalidCmd('display require at least one argument')
1898
1899 if args[0] == "options":
1900 outstr = "Value of current Options:\n"
1901 for key, value in self.options.items():
1902 outstr += '%25s \t:\t%s\n' %(key,value)
1903 output.write(outstr)
1904
1905 elif args[0] == "variable":
1906 outstr = "Value of Internal Variable:\n"
1907 try:
1908 var = eval(args[1])
1909 except Exception:
1910 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
1911 else:
1912 outstr += 'GLOBAL:\n'
1913 outstr += misc.nice_representation(var, nb_space=4)
1914
1915 try:
1916 var = eval('self.%s' % args[1])
1917 except Exception:
1918 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
1919 else:
1920 outstr += 'LOCAL:\n'
1921 outstr += misc.nice_representation(var, nb_space=4)
1922 split = args[1].split('.')
1923 for i, name in enumerate(split):
1924 try:
1925 __import__('.'.join(split[:i+1]))
1926 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1])))
1927 except ImportError:
1928 try:
1929 var = eval(args[1])
1930 except Exception as error:
1931 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1]
1932 break
1933 else:
1934 outstr += 'EXTERNAL:\n'
1935 outstr += misc.nice_representation(var, nb_space=4)
1936 else:
1937 var = eval(args[1])
1938 outstr += 'EXTERNAL:\n'
1939 outstr += misc.nice_representation(var, nb_space=4)
1940
1941 pydoc.pager(outstr)
1942
1943
1944 - def do_save(self, line, check=True):
1945 """Save the configuration file"""
1946
1947 args = self.split_arg(line)
1948
1949 if check:
1950 Cmd.check_save(self, args)
1951
1952
1953 if 'HOME' in os.environ and os.environ['HOME'] and \
1954 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
1955 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
1956 if hasattr(self, 'me_dir'):
1957 basedir = self.me_dir
1958 elif not MADEVENT:
1959 basedir = MG5DIR
1960 else:
1961 basedir = os.getcwd()
1962 elif MADEVENT:
1963
1964 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']:
1965 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)):
1966 base = pjoin(self.me_dir, 'Cards', config_file)
1967 basedir = self.me_dir
1968 else:
1969 if hasattr(self, 'me_dir'):
1970 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1971 if len(args) == 0 and os.path.exists(base):
1972 self.write_configuration(base, base, self.me_dir)
1973 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1974 basedir = MG5DIR
1975
1976 if len(args) == 0:
1977 args.append(base)
1978 self.write_configuration(args[0], base, basedir, self.options)
1979
1981 """Write the configuration file"""
1982
1983
1984
1985
1986 logger.info('save configuration file to %s' % filepath)
1987 to_write = list(to_keep.keys())
1988 text = ""
1989 has_mg5_path = False
1990
1991 for line in open(basefile):
1992 if '=' in line:
1993 data, value = line.split('=',1)
1994 else:
1995 text += line
1996 continue
1997 data = data.strip()
1998 if data.startswith('#'):
1999 key = data[1:].strip()
2000 else:
2001 key = data
2002 if '#' in value:
2003 value, comment = value.split('#',1)
2004 else:
2005 comment = ''
2006 if key in to_keep:
2007 value = str(to_keep[key])
2008 else:
2009 text += line
2010 continue
2011 if key == 'mg5_path':
2012 has_mg5_path = True
2013 try:
2014 to_write.remove(key)
2015 except Exception:
2016 pass
2017 if '_path' in key:
2018
2019
2020 if not os.path.isabs(value):
2021 value = os.path.realpath(os.path.join(basedir, value))
2022 text += '%s = %s # %s \n' % (key, value, comment)
2023 for key in to_write:
2024 if key in to_keep:
2025 text += '%s = %s \n' % (key, to_keep[key])
2026
2027 if not MADEVENT and not has_mg5_path:
2028 text += """\n# MG5 MAIN DIRECTORY\n"""
2029 text += "mg5_path = %s\n" % MG5DIR
2030
2031 writer = open(filepath,'w')
2032 writer.write(text)
2033 writer.close()
2034
2039 """CMD command with shell activate"""
2040
2041
2043 "Run a shell command"
2044
2045 if not line.strip():
2046 self.help_shell()
2047 else:
2048 logging.info("running shell command: " + line)
2049 subprocess.call(line, shell=True)
2050
2065
2067 """help for the shell"""
2068 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')
2069 logger.info("syntax: shell CMD (or ! CMD)",'$MG:BOLD')
2070
2074
2078 """ a class for answering a question with the path autocompletion"""
2079
2080 allowpath = False
2082 """Initializing before starting the main loop"""
2083 self.prompt = '>'
2084 self.value = None
2085 BasicCmd.preloop(self)
2086
2087 @property
2090
2091 - def __init__(self, question, allow_arg=[], default=None,
2092 mother_interface=None, *arg, **opt):
2093
2094 self.question = question
2095 self.wrong_answer = 0
2096 self.allow_arg = [str(a) for a in allow_arg]
2097 self.history_header = ''
2098 self.default_value = str(default)
2099 self.mother_interface = mother_interface
2100
2101 if 'case' in opt:
2102 self.casesensitive = opt['case']
2103 del opt['case']
2104 elif 'casesensitive' in opt:
2105 self.casesensitive = opt['casesensitive']
2106 del opt['casesensitive']
2107 else:
2108 self.casesensistive = True
2109 super(SmartQuestion, self).__init__(*arg, **opt)
2110
2111 - def __call__(self, question, reprint_opt=True, **opts):
2112
2113 self.question = question
2114 for key,value in opts:
2115 setattr(self, key, value)
2116 if reprint_opt:
2117 print(question)
2118 logger_tuto.info("Need help here? type 'help'", '$MG:BOLD')
2119 logger_plugin.info("Need help here? type 'help'" , '$MG:BOLD')
2120 return self.cmdloop()
2121
2122
2124 prev_timer = signal.alarm(0)
2125 if prev_timer:
2126 nb_back = len(line)
2127 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2128 self.stdout.write(line)
2129 self.stdout.flush()
2130 try:
2131 out = {}
2132 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2133 out[' Recognized command'] = super(SmartQuestion, self).completenames(text,line, *ignored)
2134
2135 return self.deal_multiple_categories(out)
2136 except Exception as error:
2137 print(error)
2138
2139 completedefault = completenames
2140
2142
2143
2144 return dir(self)
2145
2146 - def onecmd(self, line, **opt):
2147 """catch all error and stop properly command accordingly
2148 Interpret the argument as though it had been typed in response
2149 to the prompt.
2150
2151 The return value is a flag indicating whether interpretation of
2152 commands by the interpreter should stop.
2153
2154 This allow to pass extra argument for internal call.
2155 """
2156 try:
2157 if '~/' in line and 'HOME' in os.environ:
2158 line = line.replace('~/', '%s/' % os.environ['HOME'])
2159 line = os.path.expandvars(line)
2160 cmd, arg, line = self.parseline(line)
2161 if not line:
2162 return self.emptyline()
2163 if cmd is None:
2164 return self.default(line)
2165 self.lastcmd = line
2166 if cmd == '':
2167 return self.default(line)
2168 else:
2169 try:
2170 func = getattr(self, 'do_' + cmd)
2171 except AttributeError:
2172 return self.default(line)
2173 return func(arg, **opt)
2174 except Exception as error:
2175 logger.warning(error)
2176 if __debug__:
2177 raise
2178
2179 - def reask(self, reprint_opt=True):
2180 pat = re.compile('\[(\d*)s to answer\]')
2181 prev_timer = signal.alarm(0)
2182
2183 if prev_timer:
2184 if pat.search(self.question):
2185 timeout = int(pat.search(self.question).groups()[0])
2186 signal.alarm(timeout)
2187 if reprint_opt:
2188 if not prev_timer:
2189 self.question = pat.sub('',self.question)
2190 print(self.question)
2191
2192 if self.mother_interface:
2193 answer = self.mother_interface.check_answer_in_input_file(self, 'EOF',
2194 path=self.allowpath)
2195 if answer:
2196 stop = self.default(answer)
2197 self.postcmd(stop, answer)
2198 return False
2199
2200 return False
2201
2203
2204 text=line
2205 out ={}
2206 out['Options'] = Cmd.list_completion(text, self.allow_arg)
2207 out['command'] = BasicCmd.completenames(self, text)
2208
2209 if not text:
2210 if out['Options']:
2211 logger.info( "Here is the list of all valid options:", '$MG:BOLD')
2212 logger.info( " "+ "\n ".join(out['Options']))
2213 if out['command']:
2214 logger.info( "Here is the list of command available:", '$MG:BOLD')
2215 logger.info( " "+ "\n ".join(out['command']))
2216 else:
2217 if out['Options']:
2218 logger.info( "Here is the list of all valid options starting with \'%s\'" % text, '$MG:BOLD')
2219 logger.info( " "+ "\n ".join(out['Options']))
2220 if out['command']:
2221 logger.info( "Here is the list of command available starting with \'%s\':" % text, '$MG:BOLD')
2222 logger.info( " "+ "\n ".join(out['command']))
2223 elif not out['Options']:
2224 logger.info( "No possibility starting with \'%s\'" % text, '$MG:BOLD')
2225 logger.info( "You can type help XXX, to see all command starting with XXX", '$MG:BOLD')
2229
2231 """Default action if line is not recognized"""
2232
2233 if line.strip() == '' and self.default_value is not None:
2234 self.value = self.default_value
2235 else:
2236 self.value = line
2237
2239 """If empty line, return default"""
2240
2241 if self.default_value is not None:
2242 self.value = self.default_value
2243
2244
2245 - def postcmd(self, stop, line):
2246
2247 try:
2248 if self.value in self.allow_arg:
2249 return True
2250 elif str(self.value) == 'EOF':
2251 self.value = self.default_value
2252 return True
2253 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2254 return self.reask()
2255 elif self.value in ['repeat', 'reask']:
2256 return self.reask()
2257 elif len(self.allow_arg)==0:
2258 return True
2259 elif ' ' in line.strip() and '=' in self.value:
2260 line,n = re.subn(r'\s*=\s*', '=', line)
2261 if n:
2262 self.default(line)
2263 return self.postcmd(stop, line)
2264 if not self.casesensitive:
2265 for ans in self.allow_arg:
2266 if ans.lower() == self.value.lower():
2267 self.value = ans
2268 return True
2269 break
2270 else:
2271 raise Exception
2272
2273
2274 else:
2275 raise Exception
2276 except Exception as error:
2277 if self.wrong_answer < 100:
2278 self.wrong_answer += 1
2279 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
2280 % (self.value,','.join(self.allow_arg)))
2281 logger.warning('please retry')
2282 return False
2283 else:
2284 self.value = self.default_value
2285 return True
2286
2290
2296
2301 """ a class for answering a question with the path autocompletion"""
2302
2303 completion_prefix=''
2304 allowpath=True
2305
2306 - def completenames(self, text, line, begidx, endidx, formatting=True):
2307 prev_timer = signal.alarm(0)
2308 if prev_timer:
2309 nb_back = len(line)
2310 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2311 self.stdout.write(line)
2312 self.stdout.flush()
2313
2314 try:
2315 out = {}
2316 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2317 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
2318 out[' Recognized command'] = BasicCmd.completenames(self, text, line, begidx, endidx)
2319
2320 return self.deal_multiple_categories(out, formatting)
2321 except Exception as error:
2322 print(error)
2323
2329
2331 prev_timer = signal.alarm(0)
2332 if prev_timer:
2333 nb_back = len(line)
2334 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2335 self.stdout.write(line)
2336 self.stdout.flush()
2337 try:
2338 args = Cmd.split_arg(line[0:begidx])
2339 except Exception as error:
2340 print(error)
2341
2342
2343 if args[-1].endswith(os.path.sep):
2344
2345 return Cmd.path_completion(text,
2346 os.path.join('.',*[a for a in args \
2347 if a.endswith(os.path.sep)]),
2348 begidx, endidx)
2349 return self.completenames(text, line, begidx, endidx)
2350
2351
2352 - def postcmd(self, stop, line):
2353 try:
2354 if self.value in self.allow_arg:
2355 return True
2356 elif self.value and os.path.isfile(self.value):
2357 return os.path.relpath(self.value)
2358 elif self.value and str(self.value) == 'EOF':
2359 self.value = self.default_value
2360 return True
2361 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2362
2363 reprint_opt = True
2364 elif self.value in ['repeat', 'reask']:
2365 reprint_opt = True
2366 else:
2367 raise Exception
2368 except Exception as error:
2369 print("""not valid argument. Valid argument are file path or value in (%s).""" \
2370 % ','.join(self.allow_arg))
2371 print('please retry')
2372 reprint_opt = False
2373
2374 if line != 'EOF':
2375 return self.reask(reprint_opt)
2376
2383
2387 """A class for asking a question on which program to run.
2388 This is the abstract class
2389
2390 Behavior for each switch can be customize via:
2391 set_default_XXXX() -> set default value
2392 This is super-seeded by self.default_switch if that attribute is defined (and has a key for XXXX)
2393 get_allowed_XXXX() -> return list of possible value
2394 check_value_XXXX(value) -> return True/False if the user can set such value
2395 switch_off_XXXXX() -> set it off (called for special mode)
2396 color_for_XXXX(value) -> return the representation on the screen for value
2397 get_cardcmd_for_XXXX(value)> return the command to run to customize the cards to
2398 match the status
2399 print_options_XXXX() -> return the text to disply below "other options"
2400 default is other possible value (ordered correctly)
2401
2402 consistency_XX_YY(val_XX, val_YY)
2403 -> XX is the new key set by the user to a new value val_XX
2404 -> YY is another key set by the user.
2405 -> return value should be None or "replace_YY"
2406
2407 consistency_XX(val_XX):
2408 check the consistency of the other switch given the new status of this one.
2409 return a dict {key:replaced_value} or {} if nothing to do
2410
2411 user typing "NAME" will result to a call to self.ans_NAME(None)
2412 user typing "NAME=XX" will result to a call to self.ans_NAME('XX')
2413
2414 Note on case sensitivity:
2415 -------------------------
2416 the XXX is displayed with the case in self.to_control
2417 but ALL functions should use the lower case version.
2418 for key associated to get_allowed_keys(),
2419 if (user) value not in that list.
2420 -> try to find the first entry matching up to the case
2421 for ans_XXX, set the value to lower case, but if case_XXX is set to True
2422 """
2423
2424 case_sensitive = False
2425 quit_on = ['0','done', 'EOF','','auto']
2426
2427 - def __init__(self, to_control, motherinstance, *args, **opts):
2428 """to_control is a list of ('KEY': 'Choose the shower/hadronization program')
2429 """
2430
2431 self.to_control = to_control
2432 self.mother_interface = motherinstance
2433 self.inconsistent_keys = {}
2434
2435
2436 self.inconsistent_details = {}
2437 self.last_changed = []
2438
2439
2440 self.switch = {}
2441 for key, _ in to_control:
2442 self.switch[key.lower()] = 'temporary'
2443
2444 self.set_default_switch()
2445 question = self.create_question()
2446
2447
2448 allowed_args = [ repr(i)+';' for i in range(1, 1+len(self.to_control))]
2449 for key in self.switch:
2450 allowed_args += ['%s=%s;' % (key,s) for s in self.get_allowed(key)]
2451
2452 allowed_args += [key[4:]+';' for key in dir(self) if key.startswith('ans_')]
2453 allowed_args += [arg[:-1] for arg in allowed_args if arg[-1] == ';']
2454 if 'allow_arg' in opts:
2455 allowed_args += opts['allow_arg']
2456 del opts['allow_arg']
2457
2458 allowed_args +=["0", "done"]
2459 SmartQuestion.__init__(self, question, allowed_args, *args, **opts)
2460 self.options = self.mother_interface.options
2461
2488
2489
2490
2491
2492
2494
2495 for key,_ in self.to_control:
2496 key = key.lower()
2497 if hasattr(self, 'default_switch') and key in self.default_switch:
2498 self.switch[key] = self.default_switch[key]
2499 continue
2500 if hasattr(self, 'set_default_%s' % key):
2501 getattr(self, 'set_default_%s' % key)()
2502 else:
2503 self.default_switch_for(key)
2504
2506 """use this if they are no dedicated function for such key"""
2507
2508 if hasattr(self, 'get_allowed_%s' % key):
2509 return getattr(self, 'get_allowed_%s' % key)()[0]
2510 else:
2511 self.switch[key] = 'OFF'
2512
2514 """set all valid parameter to OFF --call before special keyword--
2515 """
2516
2517 for key in self.switch:
2518 if hasattr(self, 'switch_off_%s' % key):
2519 getattr(self, 'switch_off_%s' % key)()
2520 elif self.check_value(key, self.switch[key]):
2521 self.switch[key] = 'OFF'
2522 self.inconsistent_details = {}
2523 self.inconsistent_keys = {}
2524
2525
2527 """return True/False if the value is a correct value to be set by the USER.
2528 other value than those can be set by the system --like-- Not available.
2529 This does not check the full consistency of the switch
2530 """
2531
2532 if hasattr(self, 'check_value_%s' % key):
2533 return getattr(self, 'check_value_%s' % key)(value)
2534 elif value in self.get_allowed(key):
2535 return True
2536 else:
2537 return False
2538
2539
2541 """ return the list of command that need to be run to have a consistent
2542 set of cards with the switch value choosen """
2543
2544 switch = self.answer
2545 cmd= []
2546 for key in self.switch:
2547 if hasattr(self, 'get_cardcmd_for_%s' % key):
2548 cmd += getattr(self, 'get_cardcmd_for_%s' % key)(switch[key])
2549 return cmd
2550
2551
2553 """return the list of possible value for key"""
2554
2555 if hasattr(self, 'get_allowed_%s' % key):
2556 return getattr(self, 'get_allowed_%s' % key)()
2557 else:
2558 return ['ON', 'OFF']
2559
2560 - def default(self, line, raise_error=False):
2561 """Default action if line is not recognized"""
2562
2563 line=line.strip().replace('@', '__at__')
2564 if ';' in line:
2565 for l in line.split(';'):
2566 if l:
2567 out = self.default(l)
2568 return out
2569
2570 if '=' in line:
2571 base, value = line.split('=',1)
2572 base = base.strip()
2573 value = value.strip()
2574
2575 if base.isdigit() :
2576 try:
2577 base = self.to_control[int(base)-1][0]
2578 except:
2579 pass
2580 elif ' ' in line:
2581 base, value = line.split(' ', 1)
2582 elif hasattr(self, 'ans_%s' % line.lower()):
2583 base, value = line.lower(), None
2584 elif line.isdigit() and line in [repr(i) for i in range(1, len(self.to_control)+1)]:
2585
2586 base = self.to_control[int(line)-1][0].lower()
2587 return self.default(base)
2588 elif line.lower() in self.switch:
2589
2590 base = line.lower()
2591 try:
2592 cur = self.get_allowed(base).index(self.switch[base])
2593 except:
2594 if self.get_allowed(base):
2595 value = self.get_allowed(base)[0]
2596 else:
2597 logger.warning('Can not switch "%s" to another value via number', base)
2598 self.value='reask'
2599 return
2600 else:
2601 try:
2602 value = self.get_allowed(base)[cur+1]
2603 except IndexError:
2604 value = self.get_allowed(base)[0]
2605 if value == "OFF" and cur == 0:
2606 logger.warning("Invalid action: %s" % self.print_options(base))
2607 elif cur == 0:
2608 logger.warning("Can not change value for this parameter")
2609
2610
2611 elif line in ['', 'done', 'EOF', 'eof','0']:
2612 super(ControlSwitch, self).default(line)
2613 return self.answer
2614 elif line in 'auto':
2615 self.switch['dynamical'] = True
2616 return super(ControlSwitch, self).default(line)
2617 elif line.startswith('set ') and not hasattr(self.__class__, 'do_set'):
2618 raise NotValidInput('unknow command: %s. Did you mean \"%s\"' % (line, line[4:]))
2619 elif raise_error:
2620 raise NotValidInput('unknow command: %s' % line)
2621 else:
2622 logger.warning('unknow command: %s' % line)
2623 self.value = 'reask'
2624 return
2625
2626 self.value = 'reask'
2627 base = base.lower()
2628 if hasattr(self, 'ans_%s' % base):
2629 if value and not self.is_case_sensitive(base):
2630 value = value.lower()
2631 getattr(self, 'ans_%s' % base)(value)
2632 elif base in self.switch:
2633 self.set_switch(base, value)
2634 elif line.startswith('set ') and not hasattr(self.__class__, 'do_set'):
2635 raise NotValidInput('Not valid command: %s. Did you mean \"%s\"' % (line, line[4:]))
2636 elif raise_error:
2637 raise NotValidInput('Not valid command: %s' % line)
2638 else:
2639 logger.warning('Not valid command: %s' % line)
2640
2642 """check if a key is case sensitive"""
2643
2644 case = self.case_sensitive
2645 if hasattr(self, 'case_%s' % key):
2646 case = getattr(self, 'case_%s' % key)
2647 return case
2648
2649 - def onecmd(self, line, **opt):
2654
2655 @property
2657
2658
2659 for key,_ in self.to_control:
2660 if not self.check_value(key, self.switch[key]):
2661 self.switch[key] = 'OFF'
2662
2663 if not self.inconsistent_keys:
2664 return self.switch
2665 else:
2666 out = dict(self.switch)
2667 out.update(self.inconsistent_keys)
2668 return out
2669
2670 - def postcmd(self, stop, line):
2671
2672
2673
2674 try:
2675 out = super(ControlSwitch,self).postcmd(stop, line)
2676 except AttributeError:
2677 pass
2678 if out:
2679 return out
2680
2681 line = line.strip()
2682 if ';' in line:
2683 line= [l for l in line.split(';') if l][-1]
2684 if line in self.quit_on or self.value in self.quit_on:
2685 return True
2686 if self.value != 'reask':
2687 self.create_question()
2688 return self.reask(True)
2689 return
2690
2692 """change a switch to a given value"""
2693
2694 assert key in self.switch
2695
2696 if hasattr(self, 'ans_%s' % key):
2697 if not self.is_case_sensitive(key):
2698 value = value.lower()
2699 return getattr(self, 'ans_%s' % key)(value)
2700
2701 if not self.is_case_sensitive(key) and value not in self.get_allowed(key):
2702 lower = [t.lower() for t in self.get_allowed(key)]
2703 try:
2704 ind = lower.index(value.lower())
2705 except ValueError:
2706 pass
2707 else:
2708 value = self.get_allowed(key)[ind]
2709
2710 check = self.check_value(key, value)
2711 if not check:
2712 logger.warning('"%s" not valid option for "%s"', value, key)
2713 return
2714 if isinstance(check, str):
2715 value = check
2716
2717 self.switch[key] = value
2718
2719 if user:
2720 self.check_consistency(key, value)
2721
2723
2724 if not keys:
2725 self.inconsistent_keys = {}
2726 self.inconsistent_details = {}
2727 elif isinstance(keys, list):
2728 for key in keys:
2729 if key in self.inconsistent_keys:
2730 del self.inconsistent_keys[keys]
2731 del self.inconsistent_details[keys]
2732 else:
2733 if keys in self.inconsistent_keys:
2734 del self.inconsistent_keys[keys]
2735 del self.inconsistent_details[keys]
2736
2738 """check the consistency of the new flag with the old ones"""
2739
2740
2741 if key in self.last_changed:
2742 self.last_changed.remove(key)
2743 self.last_changed.append(key)
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757 if hasattr(self, 'consistency_%s' % key):
2758 rules = dict([(key2, None) for key2 in self.switch])
2759 rules.update(getattr(self, 'consistency_%s' % key)(value, self.switch))
2760 else:
2761 rules = {}
2762 for key2,value2 in self.switch.items():
2763 if hasattr(self, 'consistency_%s_%s' % (key,key2)):
2764 rules[key2] = getattr(self, 'consistency_%s_%s' % (key,key2))(value, value2)
2765
2766
2767 if rules[key2] is not None and not self.check_value(key2, rules[key2]):
2768 if rules[key2] != 'OFF':
2769 logger.debug('consistency_%s_%s returns invalid output. Assume no conflict')
2770 rules[key2] = None
2771 else:
2772 rules[key2] = None
2773
2774
2775
2776
2777
2778 self.remove_inconsistency(key)
2779
2780 for key2 in self.switch:
2781 if rules[key2]:
2782 info = {'orig_value': self.switch[key2],
2783 'changed_key': key,
2784 'new_changed_key_val': value,
2785 'replacement': rules[key2]}
2786 if key2 in self.inconsistent_details:
2787 self.inconsistent_details[key2].append(info)
2788 else:
2789 self.inconsistent_details[key2] = [info]
2790
2791 if not self.inconsistent_details:
2792 return
2793
2794
2795 for key2 in dict(self.inconsistent_details):
2796 for conflict in list(self.inconsistent_details[key2]):
2797 keep_conflict = True
2798
2799 if conflict['orig_value'] != self.switch[key2]:
2800 keep_conflict = False
2801
2802 if self.switch[conflict['changed_key']] != conflict['new_changed_key_val']:
2803 keep_conflict = False
2804 if not keep_conflict:
2805 self.inconsistent_details[key2].remove(conflict)
2806 if not self.inconsistent_details[key2]:
2807 del self.inconsistent_details[key2]
2808
2809
2810
2811
2812 tmp_switch = dict(self.switch)
2813
2814
2815 to_check = [(c['changed_key'], c['new_changed_key_val']) \
2816 for k in self.inconsistent_details.values() for c in k
2817 if c['changed_key'] != key]
2818
2819 to_check.sort(key=lambda x: self.last_changed.index(x[0]))
2820
2821
2822 to_check = [(key, value)] + to_check
2823
2824 i = 0
2825 while len(to_check) and i < 50:
2826
2827
2828 i +=1
2829 key2, value2 = to_check.pop(0)
2830 if hasattr(self, 'consistency_%s' % key2):
2831 rules2 = dict([(key2, None) for key2 in self.switch])
2832 rules2.update(getattr(self, 'consistency_%s' % key2)(value, tmp_switch))
2833 else:
2834 rules = {}
2835 for key3,value3 in self.switch.items():
2836 if hasattr(self, 'consistency_%s_%s' % (key2,key3)):
2837 rules[key3] = getattr(self, 'consistency_%s_%s' % (key2,key3))(value2, value3)
2838 else:
2839 rules[key3] = None
2840
2841 for key, replacement in rules.items():
2842 if replacement:
2843 tmp_switch[key] = replacement
2844 to_check.append((key, replacement))
2845
2846
2847
2848 pos = {}
2849 for i, (key,value) in enumerate(to_check):
2850 pos[key] = i
2851 to_check_new = []
2852 for i, (key,value) in enumerate(to_check):
2853 if pos[key] == i:
2854 to_check_new.append((key,value))
2855 to_check = to_check_new
2856 if i>=50:
2857 logger.critical('Failed to find a consistent set of switch values.')
2858
2859
2860
2861 self.inconsistent_keys = {}
2862 for key2, value2 in tmp_switch.items():
2863 if value2 != self.switch[key2]:
2864
2865 if value2 == 'OFF' and not self.check_value(key2, 'OFF'):
2866 continue
2867 self.inconsistent_keys[key2] = value2
2868
2869
2870
2871
2872 green = '\x1b[32m%s\x1b[0m'
2873 yellow = '\x1b[33m%s\x1b[0m'
2874 red = '\x1b[31m%s\x1b[0m'
2875 bold = '\x1b[01m%s\x1b[0m'
2877
2878 if consistency and key in self.inconsistent_keys:
2879 return self.color_for_value(key, self.inconsistent_keys[key], consistency=False) +\
2880 u' \u21d0 '+ self.yellow % switch_value
2881
2882 if self.check_value(key, switch_value):
2883 if hasattr(self, 'color_for_%s' % key):
2884 return getattr(self, 'color_for_%s' % key)(switch_value)
2885 if switch_value in ['OFF']:
2886
2887 return self.red % switch_value
2888 else:
2889 return self.green % switch_value
2890 else:
2891 if ' ' in switch_value:
2892 return self.bold % switch_value
2893 else:
2894 return self.red % switch_value
2895
2897
2898 if hasattr(self, 'print_options_%s' % key) and not keep_default:
2899 return getattr(self, 'print_options_%s' % key)()
2900
2901
2902 try:
2903 ind = self.get_allowed(key).index(self.switch[key])
2904 except Exception as err:
2905 options = self.get_allowed(key)
2906 else:
2907 options = self.get_allowed(key)[ind:]+ self.get_allowed(key)[:ind]
2908
2909 info = '|'.join([v for v in options if v != self.switch[key]])
2910 if info == '':
2911 info = 'Please install module'
2912 return info
2913
2914 - def do_help(self, line, list_command=False):
2915 """dedicated help for the control switch"""
2916
2917 if line:
2918 return self.print_help_for_switch(line)
2919
2920
2921 logger.info(" ")
2922 logger.info(" In order to change a switch you can:")
2923 logger.info(" - type 'NAME = VALUE' to set the switch NAME to a given value.")
2924 logger.info(" - type 'ID = VALUE' to set the switch correspond to the line ID to a given value.")
2925 logger.info(" - type 'ID' where ID is the value of the line to pass from one value to the next.")
2926 logger.info(" - type 'NAME' to set the switch NAME to the next value.")
2927 logger.info("")
2928 logger.info(" You can type 'help NAME' for more help on a given switch")
2929 logger.info("")
2930 logger.info(" Special keyword:", '$MG:BOLD')
2931 logger.info(" %s" % '\t'.join([p[4:] for p in dir(self) if p.startswith('ans_')]) )
2932 logger.info(" type 'help XXX' for more information")
2933 if list_command:
2934 super(ControlSwitch, self).do_help(line)
2935
2936
2938 """ """
2939
2940 arg = line.split()[0]
2941
2942 if hasattr(self, 'help_%s' % arg):
2943 return getattr(self, 'help_%s' % arg)('')
2944
2945 if hasattr(self, 'ans_%s' % arg):
2946 return getattr(self, 'help_%s' % arg).__doc__
2947
2948 if arg in self.switch:
2949 logger.info(" information for switch %s: ", arg, '$MG:BOLD')
2950 logger.info(" allowed value:")
2951 logger.info(" %s", '\t'.join(self.get_allowed(arg)))
2952 if hasattr(self, 'help_text_%s' % arg):
2953 logger.info("")
2954 for line in getattr(self, 'help_text_%s' % arg):
2955 logger.info(line)
2956
2957
2958
2959
3131
3133 """ create the question with correct formatting"""
3134
3135
3136
3137 try:
3138 nb_rows, nb_col = os.popen('stty size', 'r').read().split()
3139 nb_rows, nb_col = int(nb_rows), int(nb_col)
3140 except Exception as error:
3141 nb_rows, nb_col = 20, 80
3142
3143
3144 max_len_description = 0
3145 max_len_switch = 0
3146 max_len_name = 0
3147 max_len_add_info = 0
3148 max_len_potential_switch = 0
3149 max_nb_key = 1 + int(math.log10(len(self.to_control)))
3150
3151 for key, descrip in self.to_control:
3152 if len(descrip) > max_len_description: max_len_description = len(descrip)
3153 if len(key) > max_len_name: max_len_name = len(key)
3154 if key in self.inconsistent_keys:
3155 to_display = '%s < %s' % (self.switch[key], self.inconsistent_keys[key])
3156 else:
3157 to_display = self.switch[key]
3158 if len(to_display) > max_len_switch: max_len_switch=len(to_display)
3159
3160 info = self.print_options(key)
3161 if len(info)> max_len_add_info: max_len_add_info = len(info)
3162
3163 if self.get_allowed(key):
3164 max_k = max(len(k) for k in self.get_allowed(key))
3165 else:
3166 max_k = 0
3167 if max_k > max_len_potential_switch: max_len_potential_switch = max_k
3168
3169 upper_line, lower_line, f1, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3170 max_len_name, max_len_add_info,
3171 max_len_potential_switch, max_nb_key)
3172
3173 text = \
3174 ["The following switches determine which programs are run:",
3175 upper_line
3176 ]
3177
3178
3179
3180 for i,(key, descrip) in enumerate(self.to_control):
3181
3182
3183
3184 data_to_format = {'nb': i+1,
3185 'descrip': descrip,
3186 'name': key,
3187 'switch': self.color_for_value(key,self.switch[key]),
3188 'add_info': self.print_options(key),
3189 'switch_nc': self.switch[key],
3190 'strike_switch': u'\u0336'.join(' %s ' %self.switch[key].upper()) + u'\u0336',
3191 }
3192 if key in self.inconsistent_keys:
3193
3194 _,_,_, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3195 max_len_name, max_len_add_info,
3196 max_len_potential_switch, max_nb_key,
3197 key=key)
3198
3199 data_to_format['conflict_switch_nc'] = self.inconsistent_keys[key]
3200 data_to_format['conflict_switch'] = self.color_for_value(key,self.inconsistent_keys[key], consistency=False)
3201 text.append(f2 % data_to_format)
3202 else:
3203 text.append(f1 % data_to_format)
3204
3205
3206 text.append(lower_line)
3207
3208
3209 example = None
3210 for key in self.switch:
3211 if len(self.get_allowed(key)) > 1:
3212 for val in self.get_allowed(key):
3213 if val != self.switch[key]:
3214 example = (key, val)
3215 break
3216 else:
3217 continue
3218 break
3219
3220 if not example:
3221 example = ('KEY', 'VALUE')
3222
3223 if help_text:
3224 text += \
3225 ["Either type the switch number (1 to %s) to change its setting," % len(self.to_control),
3226 "Set any switch explicitly (e.g. type '%s=%s' at the prompt)" % example,
3227 "Type 'help' for the list of all valid option",
3228 "Type '0', 'auto', 'done' or just press enter when you are done."]
3229
3230
3231 if len(text) > nb_rows:
3232
3233 to_remove = [ -2,
3234 -5,
3235 -4,
3236 -3,
3237 -1,
3238 ]
3239 to_remove = to_remove[:min(len(to_remove), len(text)-nb_rows)]
3240 text = [t for i,t in enumerate(text) if i-len(text) not in to_remove]
3241
3242 self.question = "\n".join(text)
3243 return self.question
3244
3245
3246
3247
3248
3249 -class CmdFile(file):
3250 """ a class for command input file -in order to debug cmd \n problem"""
3251
3258
3260 """readline method treating correctly a line whithout \n at the end
3261 (add it)
3262 """
3263 if self.lines:
3264 line = self.lines.pop(0)
3265 else:
3266 return ''
3267
3268 if line.endswith('\n'):
3269 return line
3270 else:
3271 return line + '\n'
3272
3275
3278