What I did was:
# main
parser = Parser('blah')
try:
while True:
# http://stackoverflow.com/a/17352877/281545
cmd = shlex.split(raw_input('> ').strip())
logging.debug('command line: %s', cmd)
try:
parser.parse(cmd)
except SystemExit: # DUH http://stackoverflow.com/q/16004901/281545
pass
except KeyboardInterrupt:
pass
Where the parser:
class Parser(argparse.ArgumentParser):
def __init__(self, desc, add_h=True):
super(Parser, self).__init__(description=desc, add_help=add_h,
formatter_class=argparse.
ArgumentDefaultsHelpFormatter)
# https://docs.python.org/dev/library/argparse.html#sub-commands
self.subparsers = subparsers = self.add_subparsers(
help='sub-command help')
# http://stackoverflow.com/a/8757447/281545
subparsers._parser_class = argparse.ArgumentParser
from watcher.commands import CMDS
for cmd in CMDS: cmd()(subparsers)
def parse(self, args):
return self.parse_args(args)
And a command (CMDS=[watch.Watch]):
class Watch(Command):
class _WatchAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
# here is the actual logic of the command
logging.debug('%r %r %r' % (namespace, values, option_string))
setattr(namespace, self.dest, values)
Sync.addObserver(path=values)
CMD_NAME = 'watch'
CMD_HELP = 'Watch a directory tree for changes'
ARGUMENTS = {'path': Arg(hlp='Path to a directory to watch. May be '
'relative or absolute', action=_WatchAction)}
where:
class Command(object):
"""A command given by the users - subclasses must define the CMD_NAME,
CMD_HELP and ARGUMENTS class fields"""
def __call__(self, subparsers):
parser_a = subparsers.add_parser(self.__class__.CMD_NAME,
help=self.__class__.CMD_HELP)
for dest, arg in self.__class__.ARGUMENTS.iteritems():
parser_a.add_argument(dest=dest, help=arg.help, action=arg.action)
return parser_a
class Arg(object):
"""Wrapper around cli arguments for a command"""
def __init__(self, hlp=None, action='store'):
self.help = hlp
self.action = action
Only tried with one command so far so this is rather untested. I used the shlex and subparsers tips from comments. I had a look at the cmd module suggested by @jh314 but did not quite grok it - however I think it is the tool for the job - I am interested in an answer with code doing what I do but using the cmd module.
string.splitand thetokenizemoduleinit /path/to/dir?argparseis used to parse the command line arguments, so most likely not what you are looking for.KeyboardInterrupt? It doesn't make your program more reliable, and the world itself is so fragile...