docopt_command.py 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. from __future__ import absolute_import
  2. from __future__ import unicode_literals
  3. from inspect import getdoc
  4. from docopt import docopt
  5. from docopt import DocoptExit
  6. def docopt_full_help(docstring, *args, **kwargs):
  7. try:
  8. return docopt(docstring, *args, **kwargs)
  9. except DocoptExit:
  10. raise SystemExit(docstring)
  11. class DocoptDispatcher(object):
  12. def __init__(self, command_class, options):
  13. self.command_class = command_class
  14. self.options = options
  15. def parse(self, argv):
  16. command_help = getdoc(self.command_class)
  17. options = docopt_full_help(command_help, argv, **self.options)
  18. command = options['COMMAND']
  19. if command is None:
  20. raise SystemExit(command_help)
  21. handler = get_handler(self.command_class, command)
  22. docstring = getdoc(handler)
  23. if docstring is None:
  24. raise NoSuchCommand(command, self)
  25. command_options = docopt_full_help(docstring, options['ARGS'], options_first=True)
  26. return options, handler, command_options
  27. def get_handler(command_class, command):
  28. command = command.replace('-', '_')
  29. # we certainly want to have "exec" command, since that's what docker client has
  30. # but in python exec is a keyword
  31. if command == "exec":
  32. command = "exec_command"
  33. if not hasattr(command_class, command):
  34. raise NoSuchCommand(command, command_class)
  35. return getattr(command_class, command)
  36. class NoSuchCommand(Exception):
  37. def __init__(self, command, supercommand):
  38. super(NoSuchCommand, self).__init__("No such command: %s" % command)
  39. self.command = command
  40. self.supercommand = supercommand