With argparse are subparsers inherently mutually e

2020-07-26 14:08发布

问题:

I have a script with two primary functions, upgrade and provision. I'm using subparsers as a way to dictate the action being performed by the script but I want to avoid them being used together.

This is a snippet of the code:

import argparse

def main():
    parser = argparse.ArgumentParser()
    subparser = parser.add_subparsers(help='sub-command help')
    parser.add_argument('--user', '-u', help='User', default=None, required=True)
    parser.add_argument('--password', '-p', help='Password', default=None, required=True)
    parser.add_argument('--server', '-s', help='server with Admin functionality', default=None, required=True)
    subparser_prov = subparser.add_parser('provision', help='Provision new managers')
    subparser_prov.set_defaults(which='provision')
    subparser_upgr = subparser.add_parser('upgrade', help='Upgrade worker by replacing them')
    subparser_upgr.set_defaults(which='upgrade')
    subparser_upgr.add_argument('--version', help='Deployment version', default=None)
    args = vars(parser.parse_args())

    print args['user']
    print args['password']

    if args['which'] == 'provision':
        print 'Provisioning new environment!'
    elif args['which'] == 'upgrade':
        print 'Upgrading workers! %s' % args['version']

if __name__ == "__main__":
    main()

I know that add_mutually_exclusive_group() is supported by both parser and subparser however this is specifically for arguments. With a subparser is there any method for avoiding them being used together?

回答1:

Yes, they are mutually exclusive, though the mechanism is different from the MXGroups.

subparser = parser.add_subparsers(help='sub-command help')

is an add_argument command that creates a positional argument, with a special action class. Among other things it has a choices value.

subparser.add_parser(...)

creates a parser, and adds its 'name' (and aliases) to subparser's choices.

A positional argument is parsed only once, so only one subparser will be handled. And the subparser usually processes all of the remaining arguments.

There have been SO questions that ask about getting around that - that is they want to handle multiple subparsers. The way to do that is tricky, and involves calling a parser recursively (or repeatedly), each time with a smaller set of the original arguments.



回答2:

As far as I can tell subparsers are mutually exclusive by default:

Note that the object returned by parse_args() will only contain attributes for the main parser and the subparser that was selected by the command line (and not any other subparsers). So in the example above, when the a command is specified, only the foo and bar attributes are present, and when the b command is specified, only the foo and baz attributes are present.

From the python documentation on subparsers.