Python中的gem/git风格命令行参数

26

是否有一个Python模块可以 处理 gem/git风格的命令行参数?我所指的gem/git风格是:

$ ./MyApp.py
The most commonly used MyApp commands are:
  add        Add file contents to the index
  bisect     Find by binary search the change that introduced a bug
  branch     List, create, or delete branches
  checkout   Checkout a branch or paths to the working tree
  ...

$ ./MyApp.py branch
  * current-branch
    master

没有传入参数时,输出会告诉你如何继续进行。而且还有一个特殊的“help”命令:

$ ./MyApp.py help branch

这可以让你更深入地了解“branch”命令的技巧。

编辑:我指的是它会为您打印用法信息,对无效输入退出,根据您的CLI规范运行您的函数。有点像命令行的“URL映射器”。

3个回答

38

是的,argparse 配合 add_subparsers() 使用。

Sub-commands 部分都有很好的解释。

可以从那里复制一个例子:

>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers()
>>> checkout = subparsers.add_parser('checkout', aliases=['co'])
>>> checkout.add_argument('foo')
>>> parser.parse_args(['checkout', 'bar'])
Namespace(foo='bar')

编辑: 很遗憾,没有自动生成特殊help命令,但您可以获得详细的帮助信息(似乎是您想要的)通过在命令后使用-h--help,就像通常一样:

$ ./MyApp.py branch --help

当我说“verbose”时,我的意思并不是像man页面那样冗长,而是像其他--help类型的帮助一样:列出所有参数等等...

例如:

>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers(description='Sub description')
>>> checkout = subparsers.add_parser('checkout', description='Checkout description')
>>> checkout.add_argument('foo', help='This is the foo help')
>>> parser.parse_args(['checkout', '--help'])
usage:  checkout [-h] foo

Checkout description

positional arguments:
  foo         This is the foo help

optional arguments:
  -h, --help  show this help message and exit

如果需要的话,实现一个重定向到--helphelp命令应该很容易。

值得一提的是,subparsers.add_parser()中的aliases关键字是Python 3中的新功能,不适用于Python 2.7。 - Juan
小心使用argparse:一旦开始添加嵌套的子解析器,事情会变得非常混乱。请看以下链接作为例子:http://bugs.python.org/issue9253 - Federico
伟大的click包已经内置了这个功能!在这里查看复杂教程here - Jaime Rodríguez-Guerra
请注意,parse_args() 返回的对象仅包含主解析器和由命令行选择的子解析器的属性(而不包括任何其他子解析器)。因此,在上面的示例中,当指定 a 命令时,只有 foo 和 bar 属性存在,当指定 b 命令时,只有 foo 和 baz 属性存在。您知道是否有任何方法可以检测到调用了哪个子解析器吗? - MoralCode
不用在意。如果你想检查哪个子解析器被调用了,在你的add_subparsers()调用中添加dest选项:https://dev59.com/7Gsy5IYBdhLWcg3w4x_c#9286586 - MoralCode

6

获取gem/git风格的“帮助”行为的一个合理技巧(我只是为我正在处理的事情而编写了这个):

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='sub_commands')
parser_branch = subparsers.add_parser('branch', description='list of branches')
parser_help = subparsers.add_parser('help')
parser_help.add_argument('command', nargs="?", default=None)

# I can't find a legitimate way to set a default subparser in the docs
#   If you know of one, please let me know!
if len(sys.argv) < 2:
    sys.argv.append('--help')

parsed = parser.parse_args()

if parsed.sub_commands == "help":
    if not parsed.command:
        parser.parse_args(['--help'])
    else:
        parser.parse_args([parsed.command, '--help'])

argparse相比于optparse和其他我接触过的Python解决方案,确实有很大进步。但在我的看法中,处理参数的宝石/ Git风格只是更加逻辑和安全的做事方式,因此不支持这种方式令人非常烦恼。


1
我希望能够像git命令一样做些事情,其中一个命令行选项会加载第二个脚本,并使该脚本填充更多的命令行选项,同时也可以使用帮助功能。
我通过禁用帮助选项、解析已知参数、添加更多参数、重新启用帮助选项,然后解析其余参数来实现这一点。
这就是我想到的方法。
import argparse 
#Note add_help=False
arg_parser = argparse.ArgumentParser(description='Add more arguments after parsing.',add_help=False)
arg_parser.add_argument('MODE',  default='default',type=str, help='What commands to use')


args = arg_parser.parse_known_args()[0]

if args.MODE == 'branch':
   arg_parser.add_argument('-d', '--delete', default='Delete a branch')
   arg_parser.add_argument('-m', '--move', default='move a branch')
elif args.MODE == 'clone' :
   arg_parser.add_argument('--local', '-l')
   arg_parser.add_argument('--shared')

#Finally re-enable the help option, and reparse the arguments
arg_parser.add_argument(
            '-h', '--help',
            action='help', default=argparse.SUPPRESS,
            help=argparse._('show this help message and exit'))

args = arg_parser.parse_args()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接