cannot have multiple subparser arguments

2019-08-23 14:20发布

So i'm trying to build an CLI with the following pattern:

cli.py api new --config config.json

or

cli.py api del [api_name]

To achieve the api i've added it as sup parser

if __name__ == '__main__':

    parser = argparse.ArgumentParser(prog='my prog')
    subparsers = parser.add_subparsers(title='api', help='available actions')

    api_parser = subparsers.add_parser('api')

from here i thought that we might want to add two new subparsers to handle the new and del subcommands:

if __name__ == '__main__':

    parser = argparse.ArgumentParser(prog='my prog')
    subparsers = parser.add_subparsers(title='api', help='available actions')

    api_parser = subparsers.add_parser('api')

    api_new_subparsers = api_parser.add_subparsers(title='new', help='%(prog)s creates new api gateway')
    api_del_subparsers = api_parser.add_subparsers(title='del', help='%(prog)s deletes an api gateway')

but i got the error: cannot have multiple subparser arguments

I've searched a bit. Most of the questions are about the following pattenr cli.py cmdA and cli.py cmdB. So i started thinking that argparse maybe is not able to achieve such kind of "depth"?

Thanks a lot.

1条回答
霸刀☆藐视天下
2楼-- · 2019-08-23 14:37

First, I'm not sure you understand the purpose of the title parameter.

In [332]: parser = argparse.ArgumentParser(prog='my prog')
     ...: subparsers = parser.add_subparsers(title='api', help='available actions')
     ...: api_parser = subparsers.add_parser('api')
     ...: 
In [333]: parser.print_help()
usage: my prog [-h] {api} ...

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

api:
  {api}       available actions
In [334]: parser.parse_args('api'.split())
Out[334]: Namespace()

All title does is define a group in the help. It doesn't change parsing. Defining a dest instead of title (or in addition to):

In [335]: parser = argparse.ArgumentParser(prog='my prog')
     ...: subparsers = parser.add_subparsers(dest='cmd', help='available actions')
     ...: api_parser = subparsers.add_parser('api')
     ...: 
In [336]: parser.print_help()
usage: my prog [-h] {api} ...

positional arguments:
  {api}       available actions

optional arguments:
  -h, --help  show this help message and exit
In [337]: parser.parse_args('api'.split())
Out[337]: Namespace(cmd='api')

This identifies the subparser command in the args namespace.

But on to the question of multiple subparsers - argparse does not allow you to define that. You can nest them. That is you could use

sp2 = api_parser.add_subparsers(dest='foo')
sp2.add_parser('del')
sp2.add_parser('inc')

In [339]: parser.parse_args('api del'.split())
Out[339]: Namespace(cmd='api', foo='del')
In [340]: parser.parse_args('api inc'.split())
Out[340]: Namespace(cmd='api', foo='inc')
In [341]: parser.parse_args('api -h'.split())
usage: my prog api [-h] {del,inc} ...

positional arguments:
  {del,inc}

But before you get too far in that direction, have you tried adding plain arguments the api_parser? Help display gets messy the deeper you go with subparsers.

Or may be you don't need the full subparser mechanism. For example defining two positionals with choices:

In [345]: parser = argparse.ArgumentParser(prog='my prog')
     ...: parser.add_argument('cmd1', choices=['api'], help='available actions')
     ...: ;
     ...: parser.add_argument('cmd2', choices=['del','inc']);
     ...: 
In [347]: parser.parse_args('api inc'.split())
Out[347]: Namespace(cmd1='api', cmd2='inc')
In [348]: parser.parse_args('-h'.split())
usage: my prog [-h] {api} {del,inc}

positional arguments:
  {api}       available actions
  {del,inc}
查看更多
登录 后发表回答