PageRenderTime 465ms CodeModel.GetById 291ms app.highlight 17ms RepoModel.GetById 154ms app.codeStats 1ms

/Demo/pdist/cmdfw.py

http://unladen-swallow.googlecode.com/
Python | 144 lines | 135 code | 3 blank | 6 comment | 2 complexity | 7153f2b7f0c487ae57fa545e17ef108e MD5 | raw file
  1"Framework for command line interfaces like CVS.  See class CmdFrameWork."
  2
  3
  4class CommandFrameWork:
  5
  6    """Framework class for command line interfaces like CVS.
  7
  8    The general command line structure is
  9
 10            command [flags] subcommand [subflags] [argument] ...
 11
 12    There's a class variable GlobalFlags which specifies the
 13    global flags options.  Subcommands are defined by defining
 14    methods named do_<subcommand>.  Flags for the subcommand are
 15    defined by defining class or instance variables named
 16    flags_<subcommand>.  If there's no command, method default()
 17    is called.  The __doc__ strings for the do_ methods are used
 18    for the usage message, printed after the general usage message
 19    which is the class variable UsageMessage.  The class variable
 20    PostUsageMessage is printed after all the do_ methods' __doc__
 21    strings.  The method's return value can be a suggested exit
 22    status.  [XXX Need to rewrite this to clarify it.]
 23
 24    Common usage is to derive a class, instantiate it, and then call its
 25    run() method; by default this takes its arguments from sys.argv[1:].
 26    """
 27
 28    UsageMessage = \
 29      "usage: (name)s [flags] subcommand [subflags] [argument] ..."
 30
 31    PostUsageMessage = None
 32
 33    GlobalFlags = ''
 34
 35    def __init__(self):
 36        """Constructor, present for completeness."""
 37        pass
 38
 39    def run(self, args = None):
 40        """Process flags, subcommand and options, then run it."""
 41        import getopt, sys
 42        if args is None: args = sys.argv[1:]
 43        try:
 44            opts, args = getopt.getopt(args, self.GlobalFlags)
 45        except getopt.error, msg:
 46            return self.usage(msg)
 47        self.options(opts)
 48        if not args:
 49            self.ready()
 50            return self.default()
 51        else:
 52            cmd = args[0]
 53            mname = 'do_' + cmd
 54            fname = 'flags_' + cmd
 55            try:
 56                method = getattr(self, mname)
 57            except AttributeError:
 58                return self.usage("command %r unknown" % (cmd,))
 59            try:
 60                flags = getattr(self, fname)
 61            except AttributeError:
 62                flags = ''
 63            try:
 64                opts, args = getopt.getopt(args[1:], flags)
 65            except getopt.error, msg:
 66                return self.usage(
 67                        "subcommand %s: " % cmd + str(msg))
 68            self.ready()
 69            return method(opts, args)
 70
 71    def options(self, opts):
 72        """Process the options retrieved by getopt.
 73        Override this if you have any options."""
 74        if opts:
 75            print "-"*40
 76            print "Options:"
 77            for o, a in opts:
 78                print 'option', o, 'value', repr(a)
 79            print "-"*40
 80
 81    def ready(self):
 82        """Called just before calling the subcommand."""
 83        pass
 84
 85    def usage(self, msg = None):
 86        """Print usage message.  Return suitable exit code (2)."""
 87        if msg: print msg
 88        print self.UsageMessage % {'name': self.__class__.__name__}
 89        docstrings = {}
 90        c = self.__class__
 91        while 1:
 92            for name in dir(c):
 93                if name[:3] == 'do_':
 94                    if docstrings.has_key(name):
 95                        continue
 96                    try:
 97                        doc = getattr(c, name).__doc__
 98                    except:
 99                        doc = None
100                    if doc:
101                        docstrings[name] = doc
102            if not c.__bases__:
103                break
104            c = c.__bases__[0]
105        if docstrings:
106            print "where subcommand can be:"
107            names = docstrings.keys()
108            names.sort()
109            for name in names:
110                print docstrings[name]
111        if self.PostUsageMessage:
112            print self.PostUsageMessage
113        return 2
114
115    def default(self):
116        """Default method, called when no subcommand is given.
117        You should always override this."""
118        print "Nobody expects the Spanish Inquisition!"
119
120
121def test():
122    """Test script -- called when this module is run as a script."""
123    import sys
124    class Hello(CommandFrameWork):
125        def do_hello(self, opts, args):
126            "hello -- print 'hello world', needs no arguments"
127            print "Hello, world"
128    x = Hello()
129    tests = [
130            [],
131            ['hello'],
132            ['spam'],
133            ['-x'],
134            ['hello', '-x'],
135            None,
136            ]
137    for t in tests:
138        print '-'*10, t, '-'*10
139        sts = x.run(t)
140        print "Exit status:", repr(sts)
141
142
143if __name__ == '__main__':
144    test()