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