Skip to content

Commit

Permalink
support specifying default value and type.
Browse files Browse the repository at this point in the history
  • Loading branch information
anandology committed May 1, 2009
1 parent 1324f39 commit 2e40269
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 12 deletions.
58 changes: 58 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# subcommand: Python library for creating command line applicaitons with subcommands

Subcommand is a function decorated with `subcommand.subcommand()` decorator.
Help message and options are specified in docstring.

Hello world example:

import subcommand

@subcommand.subcommand()
def hello(options, name='world'):
"""Display hello message.

Usage: hello [options] [name]

Options:

-p [--prefix] prefix : message prefix (default: hello)
-n [--repeat] n : repeat the message n times (type: int) (default: 1)
"""
for i in range(options.n):
print options.prefix + ",", name

if __name__ == "__main__":
subcommand.main()

And here is the response.

$ python hello.py hello
hello, world
$ python hello.py hello subcommand
hello, subcommand
$ python hello.py hello -p bye subcommand
bye, subcommand
$ python hello.py hello --prefix bye subcommand
bye, subcommand
$ python hello.py hello -p bye -n 3 subcommand
bye, subcommand
bye, subcommand
bye, subcommand

$ python hello.py
usage: python hello.py <subcommand> [options] [args]

Available subcommands:
hello Displays hello message.
help Describe usage of this program and its subcommands.

anand@bodhi subcommand$ python hello.py help hello
hello: Displays hello message.

Usage: hello [options] [name]

Valid Options:
-p [--prefix] prefix : message prefix (default: hello)
-n [--repeat] n : repeat the message n times (default: 1)


25 changes: 25 additions & 0 deletions example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Subcommand example.
Options:
-v [--verbose] : verbose
"""
import subcommand

@subcommand.subcommand(aliases=["co"])
def checkout(options, *args):
"""Check out a working copy from a repository.
Fake subcommand to demonstrate subcommand functionality.
Options:
-r [--revision] revision int : revision to checkout
--username username : username
--password password : password
"""
print "dummy checkout."
print "options:", options
print "args:", args
print "global options:", subcommand.global_options

if __name__ == "__main__":
subcommand.main()
36 changes: 24 additions & 12 deletions subcommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def __call__(self, args):
subcommand_lookup[cmd](args)
else:
print >> sys.stderr, "Unknown command:", cmd
print >> sys.stderr, "Type '%s help' for usage." % program_name
print >> sys.stderr, "Type '%s help' for usage." % prog.name

class SubCommand:
def __init__(self, func, name, aliases, help, options):
Expand Down Expand Up @@ -106,7 +106,10 @@ class Option(optparse.Option):
"""
def __repr__(self):
opts = self._short_opts + self._long_opts
return xrepr("Option", type=self.type, dest=self.dest, help=self.help, *opts)
kw = dict(type=self.type, dest=self.dest, help=self.help)
if self.default != ('NO', 'DEFAULT'):
kw['default'] = self.default
return xrepr("Option", *opts, **kw)

def __str__(self):
opts = self._short_opts + self._long_opts
Expand Down Expand Up @@ -148,25 +151,34 @@ def parse_option(line):
Option('-v', '--verbose', dest='verbose', help='Turn on verbose output')
>>> parse_option('-f [--config] configfile : config file')
Option('-f', '--config', dest='configfile', type='string', help='config file')
>>> parse_option('-p [--port] port int : port')
>>> parse_option('-p [--port] port : port (type: int)')
Option('-p', '--port', dest='port', type='int', help='port')
>>> parse_option('-f [--config] configfile : config file (default: hello.conf)')
Option('-f', '--config', dest='configfile', default='hello.conf', type='string', help='config file')
>>> parse_option('-p [--port] port : port (type: int)')
Option('-p', '--port', dest='port', type='int', help='port')
"""
options, help = line.rsplit(':', 1)
options, help = line.split(':', 1)

options = [x for x in re.split(" +|\[|\]", options) if x]
options, option_desc = [x for x in options if x.startswith('-')], [x for x in options if not x.startswith('-')]

opt = Option(help=help.strip(), *options)
tokens = re.split("\(([^\(\)]*)\)", help)
help = tokens[0].strip()

tokens = [t.split(':', 1) for t in tokens[1:] if ':' in t]
kw = dict((k.strip(), v.strip()) for k, v in tokens)

if 'default' in kw:
help = help + " (default: %s)" % kw['default']

opt = Option(help=help.strip(), *options, **kw)

if len(option_desc) == 0:
if option_desc:
opt.dest = option_desc[0]
else:
opt.action = "store_true"
opt.type = None
elif len(option_desc) == 1:
opt.dest = option_desc[0]
elif len(option_desc) == 2:
opt.dest = option_desc[0]
opt.type = option_desc[1]

return opt

def parse_options(options, args):
Expand Down

0 comments on commit 2e40269

Please sign in to comment.