14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Framework for command line interfaces like CVS. See class CmdFrameWork." 24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass CommandFrameWork: 54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Framework class for command line interfaces like CVS. 74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm The general command line structure is 94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm command [flags] subcommand [subflags] [argument] ... 114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm There's a class variable GlobalFlags which specifies the 134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm global flags options. Subcommands are defined by defining 144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm methods named do_<subcommand>. Flags for the subcommand are 154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm defined by defining class or instance variables named 164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm flags_<subcommand>. If there's no command, method default() 174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm is called. The __doc__ strings for the do_ methods are used 184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for the usage message, printed after the general usage message 194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm which is the class variable UsageMessage. The class variable 204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm PostUsageMessage is printed after all the do_ methods' __doc__ 214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm strings. The method's return value can be a suggested exit 224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm status. [XXX Need to rewrite this to clarify it.] 234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm Common usage is to derive a class, instantiate it, and then call its 254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm run() method; by default this takes its arguments from sys.argv[1:]. 264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """ 274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm UsageMessage = \ 294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm "usage: (name)s [flags] subcommand [subflags] [argument] ..." 304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm PostUsageMessage = None 324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm GlobalFlags = '' 344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self): 364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Constructor, present for completeness.""" 374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def run(self, args = None): 404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Process flags, subcommand and options, then run it.""" 414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm import getopt, sys 424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if args is None: args = sys.argv[1:] 434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm opts, args = getopt.getopt(args, self.GlobalFlags) 454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except getopt.error, msg: 464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return self.usage(msg) 474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.options(opts) 484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not args: 494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.ready() 504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return self.default() 514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm cmd = args[0] 534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm mname = 'do_' + cmd 544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm fname = 'flags_' + cmd 554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm method = getattr(self, mname) 574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except AttributeError: 584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return self.usage("command %r unknown" % (cmd,)) 594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm flags = getattr(self, fname) 614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except AttributeError: 624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm flags = '' 634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm opts, args = getopt.getopt(args[1:], flags) 654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except getopt.error, msg: 664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return self.usage( 674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm "subcommand %s: " % cmd + str(msg)) 684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.ready() 694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return method(opts, args) 704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def options(self, opts): 724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Process the options retrieved by getopt. 734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm Override this if you have any options.""" 744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if opts: 754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "-"*40 764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "Options:" 774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for o, a in opts: 784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print 'option', o, 'value', repr(a) 794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "-"*40 804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def ready(self): 824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Called just before calling the subcommand.""" 834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def usage(self, msg = None): 864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Print usage message. Return suitable exit code (2).""" 874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if msg: print msg 884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print self.UsageMessage % {'name': self.__class__.__name__} 894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm docstrings = {} 904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm c = self.__class__ 914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while 1: 924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for name in dir(c): 934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if name[:3] == 'do_': 944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if docstrings.has_key(name): 954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm continue 964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm doc = getattr(c, name).__doc__ 984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except: 994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm doc = None 1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if doc: 1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm docstrings[name] = doc 1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not c.__bases__: 1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm break 1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm c = c.__bases__[0] 1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if docstrings: 1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "where subcommand can be:" 1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm names = docstrings.keys() 1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm names.sort() 1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for name in names: 1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print docstrings[name] 1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.PostUsageMessage: 1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print self.PostUsageMessage 1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 2 1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def default(self): 1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Default method, called when no subcommand is given. 1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm You should always override this.""" 1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "Nobody expects the Spanish Inquisition!" 1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test(): 1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Test script -- called when this module is run as a script.""" 1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm import sys 1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm class Hello(CommandFrameWork): 1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def do_hello(self, opts, args): 1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm "hello -- print 'hello world', needs no arguments" 1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "Hello, world" 1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm x = Hello() 1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm tests = [ 1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm [], 1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ['hello'], 1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ['spam'], 1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ['-x'], 1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ['hello', '-x'], 1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm None, 1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ] 1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for t in tests: 1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print '-'*10, t, '-'*10 1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sts = x.run(t) 1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "Exit status:", repr(sts) 1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmif __name__ == '__main__': 1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm test() 145