参考资料 http://docs.python.org/dev/library/argparse.html
子命令 sub-commands
如svn命令 svn checkout, svn update, svn commit
主命令svn,子命令checkout、update和commit
argparse可通过add_subparsers 以及add_parser来达到效果。
步骤1.在顶层的解析器下,先定义一个subparsers,它是一个子命令解析的对象,用来产生子命令解析器 (注意,每个解析器,只能有一个subparsers)
步骤2.在subparsers下,分别定义所需要的子解析器(一个subparsers下可以有多个parser),子解析器间是互斥的关系,一个时刻只能匹配一个。
实例1
import argparse
####example 1############
#create top-level parser
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('--foo', action='store_true', help='foo help')
subparsers = parser.add_subparsers(help='sub-command help')
#create the parser for the 'a' command
parser_a = subparsers.add_parser('a', help='a help')
parser_a.add_argument('bar', type=int, help='bar help')
#create the parser for the 'b' command
parser_b = subparsers.add_parser('b', help='b help')
parser_b.add_argument('--baz', choices='xyz', help='baz help')
#parse some argument lists
parser.parse_args(['a','12'])
#Namespace(bar=12, foo=False)
parser.parse_args(['--foo', 'b','--baz','z'])
#Namespace(baz='Z', foo=True)
parser.parse_args(['--help'])
#usage: PROG [-h] [--foo] {a,b} ...
#
#positional arguments:
# {a,b} sub-command help
# a a help
# b b help
#
#optional arguments:
# -h, --help show this help message and exit
# --foo foo help
parser.parse_args(['a','-h'])
#usage: PROG a [-h] bar
#
#positional arguments:
# bar bar help
#
#optional arguments:
# -h, --help show this help message and exit
parser.parse_args(['b','-h'])
#usage: PROG b [-h] [--baz {x,y,z}]
#
#optional arguments:
# -h, --help show this help message and exit
# --baz {x,y,z} baz help
实例2
add_subparsers()可以添加title以及description的参数,还有dest参数(用来保存匹配出来的子解析器名)
此外,可以通过子命令解析器设置默认值set_defaults()来达到子解析器与功能函数对应关系
###########example 2 ################
#添加子命令函数
def foo(args):
print (args.x * args.y)
def bar(args):
print ('((%s))' %args.z)
#创建最上层解析器
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(title='subcommands',
description='valid subcommands',
help='additional help',
dest='subparser_name')
#创建子解析器 'foo'
parser_foo = subparsers.add_parser('foo')
parser_foo.add_argument('-x', type=int, default=1)
parser_foo.add_argument('y', type=float)
parser_foo.set_defaults(func=foo) #将函数foo 与子解析器foo绑定
#创建子解析器‘bar'
parser_bar = subparsers.add_parser('bar')
parser_bar.add_argument('z')
parser_bar.set_defaults(func=bar) #将函数bar与子解析器bar绑定
args = parser.parse_args('foo 1 -x 2'.split())
#Namespace(func=, subparser_name='foo', x=2, y=1.0)
args.func(args)
#2.0
args = parser.parse_args('bar xyzyz'.split())
#Namespace(func=, subparser_name='bar', z='xyzyz')
args.func(args)
#((xyzyz))
parser.parse_args(['-h'])
#usage: subparser_example.py [-h] {foo,bar} ...
#
#optional arguments:
# -h, --help show this help message and exit
#
#subcommands:
# valid subcommands
#
# {foo,bar} additional help
注意:
子解析器下还可以定义孙子解析器
3.实际应用例子(参考openstack cinder-manage)
现在要求有一个manager, 有 db 以及host两个子命令
db命令可以有update(更新数据库) 以及sync操作(同步数据库)
host命令可以有list操作(列出host信息)
分析
db 以及host是互斥关系,因此db 和host为子命令
而db下的update 和sync命令又是互斥关系,因此它两为db的子命令
因此全局解析器分三层,顶层,子层(db、host) 以及孙子层db.sync,db.update 和host.list
import argparse
def args(*args,**kwargs):
def _decorator(func):
func.__dict__.setdefault('args', []).insert(0, (args,kwargs))
return func
return _decorator
class Dbcommands(object):
def __init__(self):
pass
@args('version', nargs='?', default='versiondefault',
help='version help')
def sync(self, version=None):
print "do Dbcommand.sync(version=%s)." %version
def update(self):
print "do Dbcommand.update()."
class Hostcommands(object):
@args('zone', nargs='?', default="zonedefault",
help=' zone help')
def list(self,zone=None):
print "do Hostcomands.list(zone=%s)." %zone
def methods_of(obj):
result = []
for i in dir(obj):
if callable(getattr(obj, i)) and not i.startswith('_'):
result.append((i, getattr(obj, i)))
return result
def fetch_func_args(func,matchargs):
fn_args = []
for args,kwargs in getattr(func, 'args', []):
arg = args[0]
fn_args.append(getattr(matchargs, arg))
return fn_args
CATEGORIES = {
'db' : Dbcommands,
'host': Hostcommands}
if __name__ == "__main__":
top_parser = argparse.ArgumentParser(prog='top')
subparsers = top_parser.add_subparsers()
for category in CATEGORIES:
command_object = CATEGORIES[category]()
category_parser = subparsers.add_parser(category)
category_parser.set_defaults(command_object=command_object)
category_subparsers = category_parser.add_subparsers(dest='action')
for (action, action_fn) in methods_of(command_object):
parser = category_subparsers.add_parser(action)
action_kwargs = []
for args, kwargs in getattr(action_fn, 'args', []):
parser.add_argument(*args, **kwargs)
parser.set_defaults(action_fn=action_fn)
parser.set_defaults(action_kwargs=action_kwargs)
match_args = top_parser.parse_args('db sync 3'.split())
print 'match_args:',match_args
fn = match_args.action_fn
fn_args = fetch_func_args(fn,match_args)
#do the match func
fn(*fn_args)
>>match_args: Namespace(action='sync', action_fn=>, action_kwargs=[], command_object=<__main__.Dbcommands object at 0x7f67a8b1cbd0>, version='3')
do Dbcommand.sync(version=3).