Package logilab :: Package common :: Module cli
[frames] | no frames]

Source Code for Module logilab.common.cli

  1  """Command line interface helper classes. 
  2   
  3  It provides some default commands, a help system, a default readline 
  4  configuration with completion and persistent history. 
  5   
  6  Example:: 
  7   
  8      class BookShell(CLIHelper): 
  9   
 10          def __init__(self): 
 11              # quit and help are builtins 
 12              # CMD_MAP keys are commands, values are topics 
 13              self.CMD_MAP['pionce'] = _("Sommeil") 
 14              self.CMD_MAP['ronfle'] = _("Sommeil") 
 15              CLIHelper.__init__(self) 
 16   
 17          help_do_pionce = ("pionce", "pionce duree", _("met ton corps en veille")) 
 18          def do_pionce(self): 
 19              print 'nap is good' 
 20   
 21          help_do_ronfle = ("ronfle", "ronfle volume", _("met les autres en veille")) 
 22          def do_ronfle(self): 
 23              print 'fuuuuuuuuuuuu rhhhhhrhrhrrh' 
 24   
 25      cl = BookShell() 
 26   
 27  :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 
 28  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr 
 29  :license: General Public License version 2 - http://www.gnu.org/licenses 
 30  """ 
 31  __docformat__ = "restructuredtext en" 
 32   
 33  import __builtin__ 
 34  if not hasattr(__builtin__, '_'): 
 35      __builtin__._ = str 
 36   
 37   
38 -def init_readline(complete_method, histfile=None):
39 """Init the readline library if available.""" 40 try: 41 import readline 42 readline.parse_and_bind("tab: complete") 43 readline.set_completer(complete_method) 44 string = readline.get_completer_delims().replace(':', '') 45 readline.set_completer_delims(string) 46 if histfile is not None: 47 try: 48 readline.read_history_file(histfile) 49 except IOError: 50 pass 51 import atexit 52 atexit.register(readline.write_history_file, histfile) 53 except: 54 print 'readline is not available :-('
55 56
57 -class Completer :
58 """Readline completer.""" 59
60 - def __init__(self, commands):
61 self.list = commands
62
63 - def complete(self, text, state):
64 """Hook called by readline when <tab> is pressed.""" 65 n = len(text) 66 matches = [] 67 for cmd in self.list : 68 if cmd[:n] == text : 69 matches.append(cmd) 70 try: 71 return matches[state] 72 except IndexError: 73 return None
74 75
76 -class CLIHelper:
77 """An abstract command line interface client which recognize commands 78 and provide an help system. 79 """ 80 81 CMD_MAP = {'help' : _("Others"), 82 'quit' : _("Others"), 83 } 84 CMD_PREFIX = '' 85
86 - def __init__(self, histfile=None) :
87 self._topics = {} 88 self.commands = None 89 self._completer = Completer(self._register_commands()) 90 init_readline(self._completer.complete, histfile)
91
92 - def run(self):
93 """loop on user input, exit on EOF""" 94 while 1: 95 try: 96 line = raw_input('>>> ') 97 except EOFError: 98 print 99 break 100 s_line = line.strip() 101 if not s_line: 102 continue 103 args = s_line.split() 104 if args[0] in self.commands: 105 try: 106 cmd = 'do_%s' % self.commands[args[0]] 107 getattr(self, cmd)(*args[1:]) 108 except EOFError: 109 break 110 except: 111 import traceback 112 traceback.print_exc() 113 else: 114 try: 115 self.handle_line(s_line) 116 except: 117 import traceback 118 traceback.print_exc()
119
120 - def handle_line(self, stripped_line):
121 """Method to overload in the concrete class (should handle 122 lines which are not commands). 123 """ 124 raise NotImplementedError()
125 126 127 # private methods ######################################################### 128
129 - def _register_commands(self):
130 """ register available commands method and return the list of 131 commands name 132 """ 133 self.commands = {} 134 self._command_help = {} 135 commands = [attr[3:] for attr in dir(self) if attr[:3] == 'do_'] 136 for command in commands: 137 topic = self.CMD_MAP[command] 138 help_method = getattr(self, 'help_do_%s' % command) 139 self._topics.setdefault(topic, []).append(help_method) 140 self.commands[self.CMD_PREFIX + command] = command 141 self._command_help[command] = help_method 142 return self.commands.keys()
143
144 - def _print_help(self, cmd, syntax, explanation):
145 print _('Command %s') % cmd 146 print _('Syntax: %s') % syntax 147 print '\t', explanation 148 print
149 150 151 # predefined commands ##################################################### 152
153 - def do_help(self, command=None) :
154 """base input of the help system""" 155 if command in self._command_help: 156 self._print_help(*self._command_help[command]) 157 elif command is None or command not in self._topics: 158 print _("Use help <topic> or help <command>.") 159 print _("Available topics are:") 160 topics = self._topics.keys() 161 topics.sort() 162 for topic in topics: 163 print '\t', topic 164 print 165 print _("Available commands are:") 166 commands = self.commands.keys() 167 commands.sort() 168 for command in commands: 169 print '\t', command[len(self.CMD_PREFIX):] 170 171 else: 172 print _('Available commands about %s:') % command 173 print 174 for command_help_method in self._topics[command]: 175 try: 176 if callable(command_help_method): 177 self._print_help(*command_help_method()) 178 else: 179 self._print_help(*command_help_method) 180 except: 181 import traceback 182 traceback.print_exc() 183 print 'ERROR in help method %s'% ( 184 command_help_method.func_name)
185 186 help_do_help = ("help", "help [topic|command]", 187 _("print help message for the given topic/command or \ 188 available topics when no argument")) 189
190 - def do_quit(self):
191 """quit the CLI""" 192 raise EOFError()
193
194 - def help_do_quit(self):
195 return ("quit", "quit", _("quit the application"))
196