简体   繁体   中英

argparse: Change number of required positional arguments based on required choices option

I'm envisioning my application to have two main modes of operation:

  1. Read values from a file and operate on them
  2. Generate values from a range and operate on them.

My application would be invoked as:

myApp.py --type range 1000 2000

or

myApp.py --type from-file /tmp/myfile.csv

And there are several additional options that I'm omitting for brevity, but they make having a full argument processor relevant.

If I select range, I need 2 positional parameters, but if I select from-file, I only need one. Can argparse be used to enforce the correct number of positional parameters based on the type option? Maybe "choices" isn't the best argparse type to use, is there a better way?

import argparse
parser = argparse.ArgumentParser(description='myApp')

parser.add_argument('--type', '-t', choices=['range', 'from-file'], required=True,
                    help='Generate values from a range or load from a file.')
# Stuff here for argparse to enforce the correct number of positional parameters.

args = parser.parse_args()

Also, is there a good way (like built-in to argparse) to make it so that "--type" isn't needed, but I could run my application as:

myApp.py range 1000 2000

or

myApp.py from-file /tmp/myfile.csv

I would want argparse to still enforce that 'range' and 'from-file' are the only valid options, and that 2 parameters must follow 'range' or 1 parameter must follow 'from-file'.

EDIT:

I'm also fine with going with the following invocations:

myApp.py --range 1000 2000

or

myApp.py --from-file /tmp/myfile.csv

This might make the process of requiring 2 vs 1 positional parameters easier. But then I would want argparse to enforce that one of the two options was specified, and not both together. Can argparse do that?

Thanks

Use subparsers to provide different arguments for each subcommand.

import argparse


parser = argparse.ArgumentParser(description='myApp')
sp = parser.add_subparsers()

range_parser = sp.add_parser('range')
range_parser.add_argument('start')
range_parser.add_argument('end')
range_parser.set_defaults(type='range')

file_parser = sp.add_parser('from-file')
file_parser.add_argument('fname')
file_parser.set_defaults(type='file')


args = parser.parse_args()

if args.type == "range":
    start = args.start
    end = args.end
elif args.type == "from-file":
    # Maybe the file contains two lines, the start
    # and end numbers of the range.
    with open(args.file) as f:
        start = int(f.readline())
        end = int(f.readline())

Then use either myApp.py range 1000 2000 or myApp.py from-file /tmp/myfile.csv . args.type will tell you which subcommand was chosen (based on the default each subparser sets for the type attribute), and each subparser's argument is added only if that subparser is used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM