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 if hasattr(question_instance, 'answer'):
1163 value = question_instance.answer
1164
1165
1166 if not return_instance:
1167 return value
1168 else:
1169 return value, question_instance
1170
1180
1181
1183 """check import command"""
1184
1185 if '-f' in args:
1186 self.force = True
1187 args.remove('-f')
1188 if args[0] != 'command':
1189 args.set(0, 'command')
1190 if len(args) != 2:
1191 raise self.InvalidCmd('import command requires one filepath argument')
1192 if not os.path.exists(args[1]):
1193 raise 'No such file or directory %s' % args[1]
1194
1195
1279
1281 """store a line of the input file which should be executed by the higher mother"""
1282
1283 if self.mother:
1284 self.mother.store_line(line)
1285 else:
1286 self.stored_line = line
1287
1289 """return stored line and clean it"""
1290 if self.mother:
1291 value = self.mother.get_stored_line()
1292 self.mother.stored_line = None
1293 else:
1294 value = self.stored_line
1295 self.stored_line = None
1296 return value
1297
1298
1299
1301 """ """
1302
1303 if self.child:
1304 return self.child.nice_error_handling(error, line)
1305
1306 os.chdir(self.__initpos)
1307
1308 self.log = False
1309 if os.path.exists(self.debug_output):
1310 os.remove(self.debug_output)
1311 try:
1312 super(Cmd,self).onecmd('history %s' % self.debug_output.replace(' ', '\ '))
1313 except Exception as error:
1314 logger.error(error)
1315
1316 debug_file = open(self.debug_output, 'a')
1317 traceback.print_exc(file=debug_file)
1318 if hasattr(error, 'filename'):
1319 debug_file.write("Related File: %s\n" % error.filename)
1320
1321 if self.history and line == self.history[-1]:
1322 error_text = 'Command \"%s\" interrupted with error:\n' % line
1323 elif self.history:
1324 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
1325 error_text += '\"%s\" with error:\n' % self.history[-1]
1326 else:
1327 error_text = ''
1328 error_text += '%s : %s\n' % (error.__class__.__name__,
1329 str(error).replace('\n','\n\t'))
1330 error_text += self.error_debug % {'debug':self.debug_output}
1331 logger_stderr.critical(error_text)
1332
1333
1334
1335 try:
1336 self.do_display('options', debug_file)
1337 except Exception as error:
1338 debug_file.write('Fail to write options with error %s' % error)
1339
1340
1341 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']:
1342 try:
1343 ff = open(pjoin(self.me_dir, 'Cards', card))
1344 debug_file.write(ff.read())
1345 ff.close()
1346 except Exception:
1347 pass
1348
1349 if hasattr(self, 'options') and 'crash_on_error' in self.options:
1350 if self.options['crash_on_error'] is True:
1351 logger.info('stop computation due to crash_on_error=True')
1352 raise
1353 sys.exit(str(error))
1354 elif self.options['crash_on_error'] == 'never':
1355 return False
1356
1357
1358 if self.use_rawinput == False or self.inputfile:
1359 return True
1360 elif self.mother:
1361 if self.mother.use_rawinput is False:
1362 return True
1363
1364 elif self.mother.mother:
1365 if self.mother.mother.use_rawinput is False:
1366 return True
1367
1368 return False
1369
1370
1371
1373 if self.child:
1374 return self.child.nice_user_error(error, line)
1375
1376
1377 os.chdir(self.__initpos)
1378 if not self.history or line == self.history[-1]:
1379 error_text = 'Command \"%s\" interrupted with error:\n' % line
1380 else:
1381 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
1382 error_text += '\"%s\" with error:\n' % self.history[-1]
1383 error_text += '%s : %s' % (error.__class__.__name__,
1384 str(error).replace('\n','\n\t'))
1385 logger_stderr.error(error_text)
1386
1387 if hasattr(self, 'options') and 'crash_on_error' in self.options:
1388 if self.options['crash_on_error'] is True:
1389 logger.info('stop computation due to crash_on_error=True')
1390 sys.exit(str(error))
1391 elif self.options['crash_on_error'] == 'never':
1392 self.history.pop()
1393 return False
1394
1395
1396 if self.use_rawinput == False or self.inputfile:
1397 return True
1398 elif self.mother:
1399 if self.mother.use_rawinput is False:
1400 return True
1401 elif self.mother.mother:
1402 if self.mother.mother.use_rawinput is False:
1403 return True
1404
1405
1406 self.history.pop()
1407 return False
1408
1410 if self.child:
1411 return self.child.nice_user_error(error, line)
1412
1413
1414 os.chdir(self.__initpos)
1415 if not self.history or line == self.history[-1]:
1416 error_text = 'Error detected in \"%s\"\n' % line
1417 else:
1418 error_text = 'Error detected in sub-command %s\n' % self.history[-1]
1419 error_text += 'write debug file %s \n' % self.debug_output
1420 self.log = False
1421 super(Cmd,self).onecmd('history %s' % self.debug_output)
1422 debug_file = open(self.debug_output, 'a')
1423 traceback.print_exc(file=debug_file)
1424 try:
1425 error = error.encode('utf-8','backslashreplace')
1426 except:
1427 error = str(error)
1428 error_text += self.config_debug % {'debug' :self.debug_output}
1429 error_text += '%s : %s' % (error.__class__.__name__,
1430 str(error).replace('\n','\n\t'))
1431 logger_stderr.error(error_text)
1432
1433
1434 try:
1435 self.do_display('options', debug_file)
1436 except Exception as error:
1437 debug_file.write('Fail to write options with error %s' % error)
1438
1439 if hasattr(self, 'options') and 'crash_on_error' in self.options:
1440 if self.options['crash_on_error'] is True:
1441 logger.info('stop computation due to crash_on_error=True')
1442 sys.exit(str(error))
1443 elif self.options['crash_on_error'] == 'never':
1444 if self.history:
1445 self.history.pop()
1446 return False
1447
1448
1449
1450
1451 if self.use_rawinput == False or self.inputfile:
1452 return True
1453 elif self.mother:
1454 if self.mother.use_rawinput is False:
1455 return True
1456 elif self.mother.mother:
1457 if self.mother.mother.use_rawinput is False:
1458 return True
1459
1460
1461 if self.history:
1462 self.history.pop()
1463 return False
1464
1466 """Interpret the argument as though it had been typed in response
1467 to the prompt.
1468
1469 The return value is a flag indicating whether interpretation of
1470 commands by the interpreter should stop.
1471
1472 This allow to pass extra argument for internal call.
1473 """
1474 if '~/' in line and 'HOME' in os.environ:
1475 line = line.replace('~/', '%s/' % os.environ['HOME'])
1476 if '#' in line:
1477 line = line.split('#')[0]
1478
1479 line = os.path.expandvars(line)
1480 cmd, arg, line = self.parseline(line)
1481 if not line:
1482 return self.emptyline()
1483 if cmd is None:
1484 return self.default(line)
1485 self.lastcmd = line
1486 if cmd == '':
1487 return self.default(line)
1488 else:
1489 try:
1490 func = getattr(self, 'do_' + cmd)
1491 except AttributeError:
1492 return self.default(line)
1493 return func(arg, **opt)
1494
1537
1538
1539
1540 - def onecmd(self, line, **opt):
1541 """catch all error and stop properly command accordingly"""
1542
1543 try:
1544 return self.onecmd_orig(line, **opt)
1545 except BaseException as error:
1546 return self.error_handling(error, line)
1547
1548
1550 """action to perform to close nicely on a keyboard interupt"""
1551 pass
1552
1553 - def exec_cmd(self, line, errorhandling=False, printcmd=True,
1554 precmd=False, postcmd=True,
1555 child=True, **opt):
1577
1579 """for third party call, call the line with pre and postfix treatment
1580 with global error handling"""
1581
1582 return self.exec_cmd(line, errorhandling=True, precmd=True)
1583
1585 """If empty line, do nothing. Default is repeat previous command."""
1586 pass
1587
1588 - def default(self, line, log=True):
1589 """Default action if line is not recognized"""
1590
1591
1592 if log:
1593 logger.warning("Command \"%s\" not recognized, please try again" % \
1594 line.split()[0])
1595 if line.strip() in ['q', '.q', 'stop']:
1596 logger.info("If you want to quit mg5 please type \"exit\".")
1597
1598 if self.history and self.history[-1] == line:
1599 self.history.pop()
1600
1601
1602 - def do_history(self, line):
1603 """write in a file the suite of command that was used"""
1604
1605 args = self.split_arg(line)
1606
1607 self.check_history(args)
1608
1609 if len(args) == 0:
1610 logger.info('\n'.join(self.history))
1611 return
1612 elif args[0] == 'clean':
1613 self.history = []
1614 logger.info('History is cleaned')
1615 return
1616 elif args[0] == '.':
1617 output_file = os.path.join(self._export_dir, 'Cards', \
1618 'proc_card_mg5.dat')
1619 output_file = open(output_file, 'w')
1620 else:
1621 output_file = open(args[0], 'w')
1622
1623
1624 text = self.get_history_header()
1625 text += ('\n'.join(self.history) + '\n')
1626
1627
1628 output_file.write(text)
1629 output_file.close()
1630
1631 if self.log:
1632 logger.info("History written to " + output_file.name)
1633
1634 - def compile(self, *args, **opts):
1635 """ """
1636 import multiprocessing
1637 if not self.options['nb_core'] or self.options['nb_core'] == 'None':
1638 self.options['nb_core'] = multiprocessing.cpu_count()
1639 return misc.compile(nb_core=self.options['nb_core'], *args, **opts)
1640
1641 - def avoid_history_duplicate(self, line, no_break=[]):
1642 """remove all line in history (but the last) starting with line.
1643 up to the point when a line didn't start by something in no_break.
1644 (reading in reverse order)"""
1645
1646 new_history = []
1647 for i in range(1, len(self.history)+1):
1648 cur_line = self.history[-i]
1649 if i == 1:
1650 new_history.append(cur_line)
1651 elif not any((cur_line.startswith(text) for text in no_break)):
1652 to_add = self.history[:-i+1]
1653 to_add.reverse()
1654 new_history += to_add
1655 break
1656 elif cur_line.startswith(line):
1657 continue
1658 else:
1659 new_history.append(cur_line)
1660
1661 new_history.reverse()
1662 self.history[:] = new_history
1663
1664
1666
1667 if self.history:
1668 self.history.pop()
1669
1670
1671
1672 previous_store_line = self.get_stored_line()
1673
1674
1675 if isinstance(filepath, str):
1676 commandline = open(filepath).readlines()
1677 else:
1678 commandline = filepath
1679 oldinputfile = self.inputfile
1680 oldraw = self.use_rawinput
1681 self.inputfile = (l for l in commandline)
1682 self.use_rawinput = False
1683
1684
1685
1686 for line in self.inputfile:
1687
1688
1689 line = line.replace('\n', '').strip()
1690
1691 if line:
1692 self.exec_cmd(line, precmd=True)
1693 stored = self.get_stored_line()
1694 while stored:
1695 line = stored
1696 self.exec_cmd(line, precmd=True)
1697 stored = self.get_stored_line()
1698
1699
1700 if self.child:
1701 self.child.exec_cmd('quit')
1702 self.inputfile = oldinputfile
1703 self.use_rawinput = oldraw
1704
1705
1706 cmd = self
1707 while hasattr(cmd, 'mother') and cmd.mother:
1708 cmd = cmd.mother
1709 cmd.stored_line = previous_store_line
1710 return
1711
1713 """Default history header"""
1714
1715 return self.history_header
1716
1717 - def postloop(self):
1718 """ """
1719
1720 if self.use_rawinput and self.completekey:
1721 try:
1722 import readline
1723 readline.set_completer(self.old_completer)
1724 del self.old_completer
1725 except ImportError:
1726 pass
1727 except AttributeError:
1728 pass
1729
1730 args = self.split_arg(self.lastcmd)
1731 if args and args[0] in ['quit','exit']:
1732 if 'all' in args:
1733 return True
1734 if len(args) >1 and args[1].isdigit():
1735 if args[1] not in ['0', '1']:
1736 return True
1737
1738 return False
1739
1740
1741
1742
1743 @staticmethod
1750
1751 signal.signal(signal.SIGALRM, handle_alarm)
1752
1753 if fct is None:
1754 fct = six.moves.input
1755
1756 if timeout:
1757 signal.alarm(timeout)
1758 question += '[%ss to answer] ' % (timeout)
1759 try:
1760 result = fct(question)
1761 except TimeOutError:
1762 if noerror:
1763 logger.info('\nuse %s' % default)
1764 if fct_timeout:
1765 fct_timeout(True)
1766 return default
1767 else:
1768 signal.alarm(0)
1769 raise
1770 finally:
1771 signal.alarm(0)
1772 if fct_timeout:
1773 fct_timeout(False)
1774 return result
1775
1776
1777
1778
1779
1780
1781
1783 """Not in help: exit the mainloop() """
1784
1785 if self.child:
1786 self.child.exec_cmd('quit ' + line, printcmd=False)
1787 return
1788 elif self.mother:
1789 self.mother.child = None
1790 if line == 'all':
1791 self.mother.do_quit('all')
1792 pass
1793 elif line:
1794 level = int(line) - 1
1795 if level:
1796 self.mother.lastcmd = 'quit %s' % level
1797 elif self.inputfile:
1798 for line in self.inputfile:
1799 logger.warning('command not executed: %s' % line.replace('\n',''))
1800
1801 return True
1802
1803
1804 do_EOF = do_quit
1805 do_exit = do_quit
1806
1808 """Not in help: propose some usefull possible action """
1809
1810
1811 if line:
1812 return super(Cmd, self).do_help(line)
1813
1814
1815 names = self.get_names()
1816 cmds = {}
1817 names.sort()
1818
1819 prevname = ''
1820 for name in names:
1821 if name[:3] == 'do_':
1822 if name == prevname:
1823 continue
1824 prevname = name
1825 cmdname=name[3:]
1826 try:
1827 doc = getattr(self.cmd, name).__doc__
1828 except Exception:
1829 doc = None
1830 if not doc:
1831 doc = getattr(self, name).__doc__
1832 if not doc:
1833 tag = "Documented commands"
1834 elif ':' in doc:
1835 tag = doc.split(':',1)[0]
1836 else:
1837 tag = "Documented commands"
1838 if tag in cmds:
1839 cmds[tag].append(cmdname)
1840 else:
1841 cmds[tag] = [cmdname]
1842
1843 self.stdout.write("%s\n"%str(self.doc_leader))
1844 for tag in self.helporder:
1845 if tag not in cmds:
1846 continue
1847 header = "%s (type help <topic>):" % tag
1848 self.print_topics(header, cmds[tag], 15,80)
1849 for name, item in cmds.items():
1850 if name in self.helporder:
1851 continue
1852 if name == "Not in help":
1853 continue
1854 header = "%s (type help <topic>):" % name
1855 self.print_topics(header, item, 15,80)
1856
1857
1858
1859 if len(self.history) == 0:
1860 last_action_2 = last_action = 'start'
1861 else:
1862 last_action_2 = last_action = 'none'
1863
1864 pos = 0
1865 authorize = list(self.next_possibility.keys())
1866 while last_action_2 not in authorize and last_action not in authorize:
1867 pos += 1
1868 if pos > len(self.history):
1869 last_action_2 = last_action = 'start'
1870 break
1871
1872 args = self.history[-1 * pos].split()
1873 last_action = args[0]
1874 if len(args)>1:
1875 last_action_2 = '%s %s' % (last_action, args[1])
1876 else:
1877 last_action_2 = 'none'
1878
1879 logger.info('Contextual Help')
1880 logger.info('===============')
1881 if last_action_2 in authorize:
1882 options = self.next_possibility[last_action_2]
1883 elif last_action in authorize:
1884 options = self.next_possibility[last_action]
1885 else:
1886 return
1887 text = 'The following command(s) may be useful in order to continue.\n'
1888 for option in options:
1889 text+='\t %s \n' % option
1890 logger.info(text)
1891
1893 """Advanced commands: basic display"""
1894
1895 args = self.split_arg(line)
1896
1897
1898 if len(args) == 0:
1899 self.help_display()
1900 raise self.InvalidCmd('display require at least one argument')
1901
1902 if args[0] == "options":
1903 outstr = "Value of current Options:\n"
1904 for key, value in self.options.items():
1905 outstr += '%25s \t:\t%s\n' %(key,value)
1906 output.write(outstr)
1907
1908 elif args[0] == "variable":
1909 outstr = "Value of Internal Variable:\n"
1910 try:
1911 var = eval(args[1])
1912 except Exception:
1913 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
1914 else:
1915 outstr += 'GLOBAL:\n'
1916 outstr += misc.nice_representation(var, nb_space=4)
1917
1918 try:
1919 var = eval('self.%s' % args[1])
1920 except Exception:
1921 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
1922 else:
1923 outstr += 'LOCAL:\n'
1924 outstr += misc.nice_representation(var, nb_space=4)
1925 split = args[1].split('.')
1926 for i, name in enumerate(split):
1927 try:
1928 __import__('.'.join(split[:i+1]))
1929 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1])))
1930 except ImportError:
1931 try:
1932 var = eval(args[1])
1933 except Exception as error:
1934 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1]
1935 break
1936 else:
1937 outstr += 'EXTERNAL:\n'
1938 outstr += misc.nice_representation(var, nb_space=4)
1939 else:
1940 var = eval(args[1])
1941 outstr += 'EXTERNAL:\n'
1942 outstr += misc.nice_representation(var, nb_space=4)
1943
1944 pydoc.pager(outstr)
1945
1946
1947 - def do_save(self, line, check=True):
1948 """Save the configuration file"""
1949
1950 args = self.split_arg(line)
1951
1952 if check:
1953 Cmd.check_save(self, args)
1954
1955
1956 if 'HOME' in os.environ and os.environ['HOME'] and \
1957 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
1958 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
1959 if hasattr(self, 'me_dir'):
1960 basedir = self.me_dir
1961 elif not MADEVENT:
1962 basedir = MG5DIR
1963 else:
1964 basedir = os.getcwd()
1965 elif MADEVENT:
1966
1967 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']:
1968 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)):
1969 base = pjoin(self.me_dir, 'Cards', config_file)
1970 basedir = self.me_dir
1971 else:
1972 if hasattr(self, 'me_dir'):
1973 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1974 if len(args) == 0 and os.path.exists(base):
1975 self.write_configuration(base, base, self.me_dir)
1976 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1977 basedir = MG5DIR
1978
1979 if len(args) == 0:
1980 args.append(base)
1981 self.write_configuration(args[0], base, basedir, self.options)
1982
1984 """Write the configuration file"""
1985
1986
1987
1988
1989 logger.info('save configuration file to %s' % filepath)
1990 to_write = list(to_keep.keys())
1991 text = ""
1992 has_mg5_path = False
1993
1994 for line in open(basefile):
1995 if '=' in line:
1996 data, value = line.split('=',1)
1997 else:
1998 text += line
1999 continue
2000 data = data.strip()
2001 if data.startswith('#'):
2002 key = data[1:].strip()
2003 else:
2004 key = data
2005 if '#' in value:
2006 value, comment = value.split('#',1)
2007 else:
2008 comment = ''
2009 if key in to_keep:
2010 value = str(to_keep[key])
2011 else:
2012 text += line
2013 continue
2014 if key == 'mg5_path':
2015 has_mg5_path = True
2016 try:
2017 to_write.remove(key)
2018 except Exception:
2019 pass
2020 if '_path' in key:
2021
2022
2023 if not os.path.isabs(value):
2024 value = os.path.realpath(os.path.join(basedir, value))
2025 text += '%s = %s # %s \n' % (key, value, comment)
2026 for key in to_write:
2027 if key in to_keep:
2028 text += '%s = %s \n' % (key, to_keep[key])
2029
2030 if not MADEVENT and not has_mg5_path:
2031 text += """\n# MG5 MAIN DIRECTORY\n"""
2032 text += "mg5_path = %s\n" % MG5DIR
2033
2034 writer = open(filepath,'w')
2035 writer.write(text)
2036 writer.close()
2037
2042 """CMD command with shell activate"""
2043
2044
2046 "Run a shell command"
2047
2048 if not line.strip():
2049 self.help_shell()
2050 else:
2051 logging.info("running shell command: " + line)
2052 subprocess.call(line, shell=True)
2053
2068
2070 """help for the shell"""
2071 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')
2072 logger.info("syntax: shell CMD (or ! CMD)",'$MG:BOLD')
2073
2077
2081 """ a class for answering a question with the path autocompletion"""
2082
2083 allowpath = False
2085 """Initializing before starting the main loop"""
2086 self.prompt = '>'
2087 self.value = None
2088 BasicCmd.preloop(self)
2089
2090 @property
2093
2094 - def __init__(self, question, allow_arg=[], default=None,
2095 mother_interface=None, *arg, **opt):
2096
2097 self.question = question
2098 self.wrong_answer = 0
2099 self.allow_arg = [str(a) for a in allow_arg]
2100 self.history_header = ''
2101 self.default_value = str(default)
2102 self.mother_interface = mother_interface
2103
2104 if 'case' in opt:
2105 self.casesensitive = opt['case']
2106 del opt['case']
2107 elif 'casesensitive' in opt:
2108 self.casesensitive = opt['casesensitive']
2109 del opt['casesensitive']
2110 else:
2111 self.casesensistive = True
2112 super(SmartQuestion, self).__init__(*arg, **opt)
2113
2114 - def __call__(self, question, reprint_opt=True, **opts):
2115
2116 self.question = question
2117 for key,value in opts:
2118 setattr(self, key, value)
2119 if reprint_opt:
2120 print(question)
2121 logger_tuto.info("Need help here? type 'help'", '$MG:BOLD')
2122 logger_plugin.info("Need help here? type 'help'" , '$MG:BOLD')
2123 return self.cmdloop()
2124
2125
2127 prev_timer = signal.alarm(0)
2128 if prev_timer:
2129 nb_back = len(line)
2130 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2131 self.stdout.write(line)
2132 self.stdout.flush()
2133 try:
2134 out = {}
2135 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2136 out[' Recognized command'] = super(SmartQuestion, self).completenames(text,line, *ignored)
2137
2138 return self.deal_multiple_categories(out)
2139 except Exception as error:
2140 print(error)
2141
2142 completedefault = completenames
2143
2145
2146
2147 return dir(self)
2148
2149 - def onecmd(self, line, **opt):
2150 """catch all error and stop properly command accordingly
2151 Interpret the argument as though it had been typed in response
2152 to the prompt.
2153
2154 The return value is a flag indicating whether interpretation of
2155 commands by the interpreter should stop.
2156
2157 This allow to pass extra argument for internal call.
2158 """
2159 try:
2160 if '~/' in line and 'HOME' in os.environ:
2161 line = line.replace('~/', '%s/' % os.environ['HOME'])
2162 line = os.path.expandvars(line)
2163 cmd, arg, line = self.parseline(line)
2164 if not line:
2165 return self.emptyline()
2166 if cmd is None:
2167 return self.default(line)
2168 self.lastcmd = line
2169 if cmd == '':
2170 return self.default(line)
2171 else:
2172 try:
2173 func = getattr(self, 'do_' + cmd)
2174 except AttributeError:
2175 return self.default(line)
2176 return func(arg, **opt)
2177 except Exception as error:
2178 logger.warning(error)
2179 if __debug__:
2180 raise
2181
2182 - def reask(self, reprint_opt=True):
2183 pat = re.compile('\[(\d*)s to answer\]')
2184 prev_timer = signal.alarm(0)
2185
2186 if prev_timer:
2187 if pat.search(self.question):
2188 timeout = int(pat.search(self.question).groups()[0])
2189 signal.alarm(timeout)
2190 if reprint_opt:
2191 if not prev_timer:
2192 self.question = pat.sub('',self.question)
2193 print(self.question)
2194
2195 if self.mother_interface:
2196 answer = self.mother_interface.check_answer_in_input_file(self, 'EOF',
2197 path=self.allowpath)
2198 if answer:
2199 stop = self.default(answer)
2200 self.postcmd(stop, answer)
2201 return False
2202
2203 return False
2204
2206
2207 text=line
2208 out ={}
2209 out['Options'] = Cmd.list_completion(text, self.allow_arg)
2210 out['command'] = BasicCmd.completenames(self, text)
2211
2212 if not text:
2213 if out['Options']:
2214 logger.info( "Here is the list of all valid options:", '$MG:BOLD')
2215 logger.info( " "+ "\n ".join(out['Options']))
2216 if out['command']:
2217 logger.info( "Here is the list of command available:", '$MG:BOLD')
2218 logger.info( " "+ "\n ".join(out['command']))
2219 else:
2220 if out['Options']:
2221 logger.info( "Here is the list of all valid options starting with \'%s\'" % text, '$MG:BOLD')
2222 logger.info( " "+ "\n ".join(out['Options']))
2223 if out['command']:
2224 logger.info( "Here is the list of command available starting with \'%s\':" % text, '$MG:BOLD')
2225 logger.info( " "+ "\n ".join(out['command']))
2226 elif not out['Options']:
2227 logger.info( "No possibility starting with \'%s\'" % text, '$MG:BOLD')
2228 logger.info( "You can type help XXX, to see all command starting with XXX", '$MG:BOLD')
2232
2234 """Default action if line is not recognized"""
2235
2236 if line.strip() == '' and self.default_value is not None:
2237 self.value = self.default_value
2238 else:
2239 self.value = line
2240
2242 """If empty line, return default"""
2243
2244 if self.default_value is not None:
2245 self.value = self.default_value
2246
2247
2248 - def postcmd(self, stop, line):
2249
2250 try:
2251 if self.value in self.allow_arg:
2252 return True
2253 elif str(self.value) == 'EOF':
2254 self.value = self.default_value
2255 return True
2256 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2257 return self.reask()
2258 elif self.value in ['repeat', 'reask']:
2259 return self.reask()
2260 elif len(self.allow_arg)==0:
2261 return True
2262 elif ' ' in line.strip() and '=' in self.value:
2263 line,n = re.subn(r'\s*=\s*', '=', line)
2264 if n:
2265 self.default(line)
2266 return self.postcmd(stop, line)
2267 if not self.casesensitive:
2268 for ans in self.allow_arg:
2269 if ans.lower() == self.value.lower():
2270 self.value = ans
2271 return True
2272 break
2273 else:
2274 raise Exception
2275
2276
2277 else:
2278 raise Exception
2279 except Exception as error:
2280 if self.wrong_answer < 100:
2281 self.wrong_answer += 1
2282 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
2283 % (self.value,','.join(self.allow_arg)))
2284 logger.warning('please retry')
2285 return False
2286 else:
2287 self.value = self.default_value
2288 return True
2289
2293
2299
2304 """ a class for answering a question with the path autocompletion"""
2305
2306 completion_prefix=''
2307 allowpath=True
2308
2309 - def completenames(self, text, line, begidx, endidx, formatting=True):
2310 prev_timer = signal.alarm(0)
2311 if prev_timer:
2312 nb_back = len(line)
2313 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2314 self.stdout.write(line)
2315 self.stdout.flush()
2316
2317 try:
2318 out = {}
2319 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2320 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
2321 out[' Recognized command'] = BasicCmd.completenames(self, text, line, begidx, endidx)
2322
2323 return self.deal_multiple_categories(out, formatting)
2324 except Exception as error:
2325 print(error)
2326
2332
2334 prev_timer = signal.alarm(0)
2335 if prev_timer:
2336 nb_back = len(line)
2337 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2338 self.stdout.write(line)
2339 self.stdout.flush()
2340 try:
2341 args = Cmd.split_arg(line[0:begidx])
2342 except Exception as error:
2343 print(error)
2344
2345
2346 if args[-1].endswith(os.path.sep):
2347
2348 return Cmd.path_completion(text,
2349 os.path.join('.',*[a for a in args \
2350 if a.endswith(os.path.sep)]),
2351 begidx, endidx)
2352 return self.completenames(text, line, begidx, endidx)
2353
2354
2355 - def postcmd(self, stop, line):
2356 try:
2357 if self.value in self.allow_arg:
2358 return True
2359 elif self.value and os.path.isfile(self.value):
2360 return os.path.relpath(self.value)
2361 elif self.value and str(self.value) == 'EOF':
2362 self.value = self.default_value
2363 return True
2364 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2365
2366 reprint_opt = True
2367 elif self.value in ['repeat', 'reask']:
2368 reprint_opt = True
2369 else:
2370 raise Exception
2371 except Exception as error:
2372 print("""not valid argument. Valid argument are file path or value in (%s).""" \
2373 % ','.join(self.allow_arg))
2374 print('please retry')
2375 reprint_opt = False
2376
2377 if line != 'EOF':
2378 return self.reask(reprint_opt)
2379
2386
2390 """A class for asking a question on which program to run.
2391 This is the abstract class
2392
2393 Behavior for each switch can be customize via:
2394 set_default_XXXX() -> set default value
2395 This is super-seeded by self.default_switch if that attribute is defined (and has a key for XXXX)
2396 get_allowed_XXXX() -> return list of possible value
2397 check_value_XXXX(value) -> return True/False if the user can set such value
2398 switch_off_XXXXX() -> set it off (called for special mode)
2399 color_for_XXXX(value) -> return the representation on the screen for value
2400 get_cardcmd_for_XXXX(value)> return the command to run to customize the cards to
2401 match the status
2402 print_options_XXXX() -> return the text to disply below "other options"
2403 default is other possible value (ordered correctly)
2404
2405 consistency_XX_YY(val_XX, val_YY)
2406 -> XX is the new key set by the user to a new value val_XX
2407 -> YY is another key set by the user.
2408 -> return value should be None or "replace_YY"
2409
2410 consistency_XX(val_XX):
2411 check the consistency of the other switch given the new status of this one.
2412 return a dict {key:replaced_value} or {} if nothing to do
2413
2414 user typing "NAME" will result to a call to self.ans_NAME(None)
2415 user typing "NAME=XX" will result to a call to self.ans_NAME('XX')
2416
2417 Note on case sensitivity:
2418 -------------------------
2419 the XXX is displayed with the case in self.to_control
2420 but ALL functions should use the lower case version.
2421 for key associated to get_allowed_keys(),
2422 if (user) value not in that list.
2423 -> try to find the first entry matching up to the case
2424 for ans_XXX, set the value to lower case, but if case_XXX is set to True
2425 """
2426
2427 case_sensitive = False
2428 quit_on = ['0','done', 'EOF','','auto']
2429
2430 - def __init__(self, to_control, motherinstance, *args, **opts):
2431 """to_control is a list of ('KEY': 'Choose the shower/hadronization program')
2432 """
2433
2434 self.to_control = to_control
2435 if 'hide_line' in opts:
2436 self.hide_line = opts['hide_line']
2437 else:
2438 self.hide_line = []
2439
2440 self.mother_interface = motherinstance
2441 self.inconsistent_keys = {}
2442
2443
2444 self.inconsistent_details = {}
2445 self.last_changed = []
2446
2447
2448 self.switch = {}
2449 for key, _ in to_control:
2450 self.switch[key.lower()] = 'temporary'
2451
2452 self.set_default_switch()
2453 question = self.create_question()
2454
2455
2456 allowed_args = [ repr(i)+';' for i in range(1, 1+len(self.to_control))]
2457 for key in self.switch:
2458 allowed_args += ['%s=%s;' % (key,s) for s in self.get_allowed(key)]
2459
2460 allowed_args += [key[4:]+';' for key in dir(self) if key.startswith('ans_')]
2461 allowed_args += [arg[:-1] for arg in allowed_args if arg[-1] == ';']
2462 if 'allow_arg' in opts:
2463 allowed_args += opts['allow_arg']
2464 del opts['allow_arg']
2465
2466 allowed_args +=["0", "done"]
2467 SmartQuestion.__init__(self, question, allowed_args, *args, **opts)
2468 self.options = self.mother_interface.options
2469
2496
2497
2498
2499
2500
2502
2503 for key,_ in self.to_control:
2504 key = key.lower()
2505 if hasattr(self, 'default_switch') and key in self.default_switch:
2506 self.switch[key] = self.default_switch[key]
2507 continue
2508 if hasattr(self, 'set_default_%s' % key):
2509 getattr(self, 'set_default_%s' % key)()
2510 else:
2511 self.default_switch_for(key)
2512
2514 """use this if they are no dedicated function for such key"""
2515
2516 if hasattr(self, 'get_allowed_%s' % key):
2517 return getattr(self, 'get_allowed_%s' % key)()[0]
2518 else:
2519 self.switch[key] = 'OFF'
2520
2522 """set all valid parameter to OFF --call before special keyword--
2523 """
2524
2525 for key in self.switch:
2526 if hasattr(self, 'switch_off_%s' % key):
2527 getattr(self, 'switch_off_%s' % key)()
2528 elif self.check_value(key, self.switch[key]):
2529 self.switch[key] = 'OFF'
2530 self.inconsistent_details = {}
2531 self.inconsistent_keys = {}
2532
2533
2535 """return True/False if the value is a correct value to be set by the USER.
2536 other value than those can be set by the system --like-- Not available.
2537 This does not check the full consistency of the switch
2538 """
2539
2540 if hasattr(self, 'check_value_%s' % key):
2541 return getattr(self, 'check_value_%s' % key)(value)
2542 elif value in self.get_allowed(key):
2543 return True
2544 else:
2545 return False
2546
2547
2549 """ return the list of command that need to be run to have a consistent
2550 set of cards with the switch value choosen """
2551
2552 switch = self.answer
2553 cmd= []
2554 for key in self.switch:
2555 if hasattr(self, 'get_cardcmd_for_%s' % key):
2556 cmd += getattr(self, 'get_cardcmd_for_%s' % key)(switch[key])
2557 return cmd
2558
2559
2561 """return the list of possible value for key"""
2562
2563 if hasattr(self, 'get_allowed_%s' % key):
2564 return getattr(self, 'get_allowed_%s' % key)()
2565 else:
2566 return ['ON', 'OFF']
2567
2568 - def default(self, line, raise_error=False):
2569 """Default action if line is not recognized"""
2570
2571 line=line.strip().replace('@', '__at__')
2572 if ';' in line:
2573 for l in line.split(';'):
2574 if l:
2575 out = self.default(l)
2576 return out
2577
2578 if '=' in line:
2579 base, value = line.split('=',1)
2580 base = base.strip()
2581 value = value.strip()
2582
2583 if base.isdigit() :
2584 try:
2585 base = self.to_control[int(base)-1][0]
2586 except:
2587 pass
2588 elif ' ' in line:
2589 base, value = line.split(' ', 1)
2590 elif hasattr(self, 'ans_%s' % line.lower()):
2591 base, value = line.lower(), None
2592 elif line.isdigit() and line in [repr(i) for i in range(1, len(self.to_control)+1)]:
2593
2594 base = self.to_control[int(line)-1][0].lower()
2595 return self.default(base)
2596 elif line.lower() in self.switch:
2597
2598 base = line.lower()
2599 try:
2600 cur = self.get_allowed(base).index(self.switch[base])
2601 except:
2602 if self.get_allowed(base):
2603 value = self.get_allowed(base)[0]
2604 else:
2605 logger.warning('Can not switch "%s" to another value via number', base)
2606 self.value='reask'
2607 return
2608 else:
2609 try:
2610 value = self.get_allowed(base)[cur+1]
2611 except IndexError:
2612 value = self.get_allowed(base)[0]
2613 if value == "OFF" and cur == 0:
2614 logger.warning("Invalid action: %s" % self.print_options(base))
2615 elif cur == 0:
2616 logger.warning("Can not change value for this parameter")
2617
2618
2619 elif line in ['', 'done', 'EOF', 'eof','0']:
2620 super(ControlSwitch, self).default(line)
2621 return self.answer
2622 elif line in 'auto':
2623 self.switch['dynamical'] = True
2624 return super(ControlSwitch, self).default(line)
2625 elif line.startswith('set ') and not hasattr(self.__class__, 'do_set'):
2626 raise NotValidInput('unknow command: %s. Did you mean \"%s\"' % (line, line[4:]))
2627 elif raise_error:
2628 raise NotValidInput('unknow command: %s' % line)
2629 else:
2630 logger.warning('unknow command: %s' % line)
2631 self.value = 'reask'
2632 return
2633
2634 self.value = 'reask'
2635 base = base.lower()
2636 if hasattr(self, 'ans_%s' % base):
2637 if value and not self.is_case_sensitive(base):
2638 value = value.lower()
2639 getattr(self, 'ans_%s' % base)(value)
2640 elif base in self.switch:
2641 self.set_switch(base, value)
2642 elif line.startswith('set ') and not hasattr(self.__class__, 'do_set'):
2643 raise NotValidInput('Not valid command: %s. Did you mean \"%s\"' % (line, line[4:]))
2644 elif raise_error:
2645 raise NotValidInput('Not valid command: %s' % line)
2646 else:
2647 logger.warning('Not valid command: %s' % line)
2648
2650 """check if a key is case sensitive"""
2651
2652 case = self.case_sensitive
2653 if hasattr(self, 'case_%s' % key):
2654 case = getattr(self, 'case_%s' % key)
2655 return case
2656
2657 - def onecmd(self, line, **opt):
2662
2663 @property
2665
2666
2667 for key,_ in self.to_control:
2668 if not self.check_value(key, self.switch[key]):
2669 self.switch[key] = 'OFF'
2670
2671 if not self.inconsistent_keys:
2672 return self.switch
2673 else:
2674 out = dict(self.switch)
2675 out.update(self.inconsistent_keys)
2676 return out
2677
2678 - def postcmd(self, stop, line):
2679
2680
2681
2682 try:
2683 out = super(ControlSwitch,self).postcmd(stop, line)
2684 except AttributeError:
2685 pass
2686 if out:
2687 return out
2688
2689 line = line.strip()
2690 if ';' in line:
2691 line= [l for l in line.split(';') if l][-1]
2692 if line in self.quit_on or self.value in self.quit_on:
2693 return True
2694 if self.value != 'reask':
2695 self.create_question()
2696 return self.reask(True)
2697 return
2698
2700 """change a switch to a given value"""
2701
2702 assert key in self.switch
2703
2704 if hasattr(self, 'ans_%s' % key):
2705 if not self.is_case_sensitive(key):
2706 value = value.lower()
2707 return getattr(self, 'ans_%s' % key)(value)
2708
2709 if not self.is_case_sensitive(key) and value not in self.get_allowed(key):
2710 lower = [t.lower() for t in self.get_allowed(key)]
2711 try:
2712 ind = lower.index(value.lower())
2713 except ValueError:
2714 pass
2715 else:
2716 value = self.get_allowed(key)[ind]
2717
2718 check = self.check_value(key, value)
2719 if not check:
2720 logger.warning('"%s" not valid option for "%s"', value, key)
2721 return
2722 if isinstance(check, str):
2723 value = check
2724
2725 self.switch[key] = value
2726
2727 if user:
2728 self.check_consistency(key, value)
2729
2731
2732 if not keys:
2733 self.inconsistent_keys = {}
2734 self.inconsistent_details = {}
2735 elif isinstance(keys, list):
2736 for key in keys:
2737 if key in self.inconsistent_keys:
2738 del self.inconsistent_keys[keys]
2739 del self.inconsistent_details[keys]
2740 else:
2741 if keys in self.inconsistent_keys:
2742 del self.inconsistent_keys[keys]
2743 del self.inconsistent_details[keys]
2744
2746 """check the consistency of the new flag with the old ones"""
2747
2748
2749 if key in self.last_changed:
2750 self.last_changed.remove(key)
2751 self.last_changed.append(key)
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765 if hasattr(self, 'consistency_%s' % key):
2766 rules = dict([(key2, None) for key2 in self.switch])
2767 rules.update(getattr(self, 'consistency_%s' % key)(value, self.switch))
2768 else:
2769 rules = {}
2770 for key2,value2 in self.switch.items():
2771 if hasattr(self, 'consistency_%s_%s' % (key,key2)):
2772 rules[key2] = getattr(self, 'consistency_%s_%s' % (key,key2))(value, value2)
2773
2774
2775 if rules[key2] is not None and not self.check_value(key2, rules[key2]):
2776 if rules[key2] != 'OFF':
2777 logger.debug('consistency_%s_%s returns invalid output. Assume no conflict')
2778 rules[key2] = None
2779 else:
2780 rules[key2] = None
2781
2782
2783
2784
2785
2786 self.remove_inconsistency(key)
2787
2788 for key2 in self.switch:
2789 if rules[key2]:
2790 info = {'orig_value': self.switch[key2],
2791 'changed_key': key,
2792 'new_changed_key_val': value,
2793 'replacement': rules[key2]}
2794 if key2 in self.inconsistent_details:
2795 self.inconsistent_details[key2].append(info)
2796 else:
2797 self.inconsistent_details[key2] = [info]
2798
2799 if not self.inconsistent_details:
2800 return
2801
2802
2803 for key2 in dict(self.inconsistent_details):
2804 for conflict in list(self.inconsistent_details[key2]):
2805 keep_conflict = True
2806
2807 if conflict['orig_value'] != self.switch[key2]:
2808 keep_conflict = False
2809
2810 if self.switch[conflict['changed_key']] != conflict['new_changed_key_val']:
2811 keep_conflict = False
2812 if not keep_conflict:
2813 self.inconsistent_details[key2].remove(conflict)
2814 if not self.inconsistent_details[key2]:
2815 del self.inconsistent_details[key2]
2816
2817
2818
2819
2820 tmp_switch = dict(self.switch)
2821
2822
2823 to_check = [(c['changed_key'], c['new_changed_key_val']) \
2824 for k in self.inconsistent_details.values() for c in k
2825 if c['changed_key'] != key]
2826
2827 to_check.sort(key=lambda x: self.last_changed.index(x[0]))
2828
2829
2830 to_check = [(key, value)] + to_check
2831
2832 nstep = 0
2833 while len(to_check) and nstep < 50:
2834
2835 nstep +=1
2836 key2, value2 = to_check.pop(0)
2837 if hasattr(self, 'consistency_%s' % key2):
2838 rules = dict([(k, None) for k in self.switch])
2839 rules.update(getattr(self, 'consistency_%s' % key2)(value, tmp_switch))
2840 else:
2841 rules = self.check_consistency_with_all(key2)
2842
2843 for key, replacement in rules.items():
2844 if replacement:
2845 tmp_switch[key] = replacement
2846 to_check.append((key, replacement))
2847
2848
2849
2850 pos = {}
2851 for i, (key,value) in enumerate(to_check):
2852 pos[key] = i
2853 to_check_new = []
2854 for i, (key,value) in enumerate(to_check):
2855 if pos[key] == i:
2856 to_check_new.append((key,value))
2857 to_check = to_check_new
2858 if nstep >=50:
2859 logger.critical('Failed to find a consistent set of switch values.')
2860
2861
2862
2863 self.inconsistent_keys = {}
2864 for key2, value2 in tmp_switch.items():
2865 if value2 != self.switch[key2]:
2866
2867 if value2 == 'OFF' and not self.check_value(key2, 'OFF'):
2868 continue
2869 self.inconsistent_keys[key2] = value2
2870
2871
2873 rules = {}
2874 for key2,value2 in self.switch.items():
2875 if hasattr(self, 'consistency_%s_%s' % (key,key2)):
2876 rules[key2] = getattr(self, 'consistency_%s_%s' % (key,key2))(value, value2)
2877 else:
2878 rules[key2] = None
2879 return rules
2880
2881
2882
2883 green = '\x1b[32m%s\x1b[0m'
2884 yellow = '\x1b[33m%s\x1b[0m'
2885 red = '\x1b[31m%s\x1b[0m'
2886 bold = '\x1b[01m%s\x1b[0m'
2888
2889 if consistency and key in self.inconsistent_keys:
2890 return self.color_for_value(key, self.inconsistent_keys[key], consistency=False) +\
2891 u' \u21d0 '+ self.yellow % switch_value
2892
2893 if self.check_value(key, switch_value):
2894 if hasattr(self, 'color_for_%s' % key):
2895 return getattr(self, 'color_for_%s' % key)(switch_value)
2896 if switch_value in ['OFF']:
2897
2898 return self.red % switch_value
2899 else:
2900 return self.green % switch_value
2901 else:
2902 if ' ' in switch_value:
2903 return self.bold % switch_value
2904 else:
2905 return self.red % switch_value
2906
2908
2909 if hasattr(self, 'print_options_%s' % key) and not keep_default:
2910 return getattr(self, 'print_options_%s' % key)()
2911
2912
2913 try:
2914 ind = self.get_allowed(key).index(self.switch[key])
2915 except Exception as err:
2916 options = self.get_allowed(key)
2917 else:
2918 options = self.get_allowed(key)[ind:]+ self.get_allowed(key)[:ind]
2919
2920 info = '|'.join([v for v in options if v != self.switch[key]])
2921 if info == '':
2922 info = 'Please install module'
2923 return info
2924
2925 - def do_help(self, line, list_command=False):
2926 """dedicated help for the control switch"""
2927
2928 if line:
2929 return self.print_help_for_switch(line)
2930
2931
2932 logger.info(" ")
2933 logger.info(" In order to change a switch you can:")
2934 logger.info(" - type 'NAME = VALUE' to set the switch NAME to a given value.")
2935 logger.info(" - type 'ID = VALUE' to set the switch correspond to the line ID to a given value.")
2936 logger.info(" - type 'ID' where ID is the value of the line to pass from one value to the next.")
2937 logger.info(" - type 'NAME' to set the switch NAME to the next value.")
2938 logger.info("")
2939 logger.info(" You can type 'help NAME' for more help on a given switch")
2940 logger.info("")
2941 logger.info(" Special keyword:", '$MG:BOLD')
2942 logger.info(" %s" % '\t'.join([p[4:] for p in dir(self) if p.startswith('ans_')]) )
2943 logger.info(" type 'help XXX' for more information")
2944 if list_command:
2945 super(ControlSwitch, self).do_help(line)
2946
2947
2949 """ """
2950
2951 arg = line.split()[0]
2952
2953 if hasattr(self, 'help_%s' % arg):
2954 return getattr(self, 'help_%s' % arg)('')
2955
2956 if hasattr(self, 'ans_%s' % arg):
2957 return getattr(self, 'help_%s' % arg).__doc__
2958
2959 if arg in self.switch:
2960 logger.info(" information for switch %s: ", arg, '$MG:BOLD')
2961 logger.info(" allowed value:")
2962 logger.info(" %s", '\t'.join(self.get_allowed(arg)))
2963 if hasattr(self, 'help_text_%s' % arg):
2964 logger.info("")
2965 for line in getattr(self, 'help_text_%s' % arg):
2966 logger.info(line)
2967
2968
2969
2970
3141
3143 """ create the question with correct formatting"""
3144
3145
3146
3147 try:
3148 nb_rows, nb_col = os.popen('stty size', 'r').read().split()
3149 nb_rows, nb_col = int(nb_rows), int(nb_col)
3150 except Exception as error:
3151 nb_rows, nb_col = 20, 80
3152
3153
3154 max_len_description = 0
3155 max_len_switch = 0
3156 max_len_name = 0
3157 max_len_add_info = 0
3158 max_len_potential_switch = 0
3159 max_nb_key = 1 + int(math.log10(len(self.to_control)))
3160
3161
3162 for key, descrip in self.to_control:
3163 if key in self.hide_line:
3164 continue
3165
3166 if len(descrip) > max_len_description: max_len_description = len(descrip)
3167 if len(key) > max_len_name: max_len_name = len(key)
3168 if key in self.inconsistent_keys:
3169 to_display = '%s < %s' % (self.switch[key], self.inconsistent_keys[key])
3170 else:
3171 to_display = self.switch[key]
3172 if len(to_display) > max_len_switch: max_len_switch=len(to_display)
3173
3174 info = self.print_options(key)
3175 if len(info)> max_len_add_info: max_len_add_info = len(info)
3176
3177 if self.get_allowed(key):
3178 max_k = max(len(k) for k in self.get_allowed(key))
3179 else:
3180 max_k = 0
3181 if max_k > max_len_potential_switch: max_len_potential_switch = max_k
3182
3183 upper_line, lower_line, f1, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3184 max_len_name, max_len_add_info,
3185 max_len_potential_switch, max_nb_key)
3186 f3 = 0
3187
3188 text = \
3189 ["The following switches determine which programs are run:",
3190 upper_line
3191 ]
3192
3193
3194
3195 for i,(key, descrip) in enumerate(self.to_control):
3196
3197 if key in self.hide_line and not __debug__:
3198 continue
3199
3200 data_to_format = {'nb': i+1,
3201 'descrip': descrip,
3202 'name': key,
3203 'switch': self.color_for_value(key,self.switch[key]),
3204 'add_info': self.print_options(key),
3205 'switch_nc': self.switch[key],
3206 'strike_switch': u'\u0336'.join(' %s ' %self.switch[key].upper()) + u'\u0336',
3207 }
3208
3209 hidden_line = False
3210 if __debug__ and key in self.hide_line:
3211 data_to_format['descrip'] = '\x1b[32m%s\x1b[0m' % data_to_format['descrip']
3212 data_to_format['add_info'] = '\x1b[32m%s\x1b[0m' % data_to_format['add_info']
3213 data_to_format['name'] = '\x1b[32m%s\x1b[0m' % data_to_format['name']
3214 hidden_line=True
3215
3216 if key in self.inconsistent_keys:
3217
3218 _,_,_, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3219 max_len_name, max_len_add_info,
3220 max_len_potential_switch, max_nb_key,
3221 key=key)
3222
3223 data_to_format['conflict_switch_nc'] = self.inconsistent_keys[key]
3224 data_to_format['conflict_switch'] = self.color_for_value(key,self.inconsistent_keys[key], consistency=False)
3225
3226 if hidden_line:
3227 f2 = re.sub('%(\((?:name|descrip|add_info)\)-?)(\d+)s',
3228 lambda x: '%%%s%ds' % (x.group(1),int(x.group(2))+9),
3229 f2)
3230 text.append(f2 % data_to_format)
3231 elif hidden_line:
3232 if not f3:
3233 f3 = re.sub('%(\((?:name|descrip|add_info)\)-?)(\d+)s',
3234 lambda x: '%%%s%ds' % (x.group(1),int(x.group(2))+9),
3235 f1)
3236 text.append(f3 % data_to_format)
3237 else:
3238 text.append(f1 % data_to_format)
3239
3240
3241 text.append(lower_line)
3242
3243
3244 example = None
3245 for key in self.switch:
3246 if len(self.get_allowed(key)) > 1:
3247 for val in self.get_allowed(key):
3248 if val != self.switch[key]:
3249 example = (key, val)
3250 break
3251 else:
3252 continue
3253 break
3254
3255 if not example:
3256 example = ('KEY', 'VALUE')
3257
3258 if help_text:
3259 text += \
3260 ["Either type the switch number (1 to %s) to change its setting," % len(self.to_control),
3261 "Set any switch explicitly (e.g. type '%s=%s' at the prompt)" % example,
3262 "Type 'help' for the list of all valid option",
3263 "Type '0', 'auto', 'done' or just press enter when you are done."]
3264
3265
3266 if len(text) > nb_rows:
3267
3268 to_remove = [ -2,
3269 -5,
3270 -4,
3271 -3,
3272 -1,
3273 ]
3274 to_remove = to_remove[:min(len(to_remove), len(text)-nb_rows)]
3275 text = [t for i,t in enumerate(text) if i-len(text) not in to_remove]
3276
3277 self.question = "\n".join(text)
3278 return self.question
3279
3280
3281
3282
3283
3284 -class CmdFile(file):
3285 """ a class for command input file -in order to debug cmd \n problem"""
3286
3293
3295 """readline method treating correctly a line whithout \n at the end
3296 (add it)
3297 """
3298 if self.lines:
3299 line = self.lines.pop(0)
3300 else:
3301 return ''
3302
3303 if line.endswith('\n'):
3304 return line
3305 else:
3306 return line + '\n'
3307
3310
3313