2

A program I'm writing requires 1 of 3 inputs.

2 of the inputs require an additional parameter. 1 of the inputs requires 2 additional parameters. Only 1 of these can be input at a time.

How can I ensure this using the argparse module?

Please see the code below for what I've tried so far.

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('-d',  
      default='temp.file')

parser.add_argument('command',
      choices=['g', 's', 'm'])

args = parser.parse_args()
>>> prog.py g #  requires 1 param.
>>> prog.py s #  requires 1 param.
>>> prog.py m #  requires 2 params.
1
  • How do I read the next 2 params not using argparse? Commented Jul 7, 2019 at 21:42

3 Answers 3

2

g, s, and m are subcommands, which can be implemented using sub parsers.

p = ArgumentParser()
p.add_argument('-d', default='temp.file')

subparsers = p.add_subparsers()
g_parser = subparsers.add_parser('g')
g_parser.add_argument('g_foo')

s_parser = subparsers.add_parser('s')
s_parser.add_argument('s_foo')

m_parser = subparsers.add_parser('m')
m_parser.add_argument('m_foo')
m_parser.add_argument('m_bar')

When you call p.parse_args, then g_foo et al. will only appear in the result when the appropriate subcommand is used. For example:

>>> p.parse_args(['g', '3'])
Namespace(d='temp.file', g_foo='3')
>>> p.parse_args(['m', '4', '5'])
Namespace(d='temp.file', m_foo='4', m_bar='5')
Sign up to request clarification or add additional context in comments.

Comments

1

Looks like a good use for a mutually exclusive group

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('-d',  
      default='temp.file')
mx = parser.add_mutually_exclusive_group(required=True)
mx.add_argument('-g')
mx.add_argument('-s')
mx.add_argument('-m', nargs=2)

args = parser.parse_args()
print(args)

Sample runs:

1316:~/mypy$ python3 stack56926264.py -h
usage: stack56926264.py [-h] [-d D] (-g G | -s S | -m M M)

optional arguments:
  -h, --help  show this help message and exit
  -d D
  -g G
  -s S
  -m M M

1527:~/mypy$ python3 stack56926264.py -g foo
Namespace(d='temp.file', g='foo', m=None, s=None)

1528:~/mypy$ python3 stack56926264.py -s bar
Namespace(d='temp.file', g=None, m=None, s='bar')

1528:~/mypy$ python3 stack56926264.py -m 1 2
Namespace(d='temp.file', g=None, m=['1', '2'], s=None)

and catching some errors:

1528:~/mypy$ python3 stack56926264.py -m 1 2 -s bar -d afile
usage: stack56926264.py [-h] [-d D] (-g G | -s S | -m M M)
stack56926264.py: error: argument -s: not allowed with argument -m

1528:~/mypy$ python3 stack56926264.py -m 1 
usage: stack56926264.py [-h] [-d D] (-g G | -s S | -m M M)
stack56926264.py: error: argument -m: expected 2 arguments

1530:~/mypy$ python3 stack56926264.py -d afile
usage: stack56926264.py [-h] [-d D] (-g G | -s S | -m M M)
stack56926264.py: error: one of the arguments -g -s -m is required

Comments

0

What you could do is check for yourself that the arguments are in line with your logic:

parser = argparse.ArgumentParser()

parser.add_argument('-d',  
                    default='temp.file')

parser.add_argument('command',
                    choices=['g', 's', 'm'])

parser.add_argument('additionals',
                    nargs='+')

args = parser.parse_args()

if args.command in ('g', 's') and len(args.additionals) != 1:
    print("Commands g and s require 1 argument")
elif args.command == 'm' and len(args.additionals) != 2:
    print("Command m require 2 arguments")

Another way to go around this is to seperate those commands to different arguments with the corresponding number of additional arguments they require:

parser = argparse.ArgumentParser()

parser.add_argument('-d',  
                    default='temp.file')

parser.add_argument('-g',
                    nargs=1)

parser.add_argument('-s',
                    nargs=1)

parser.add_argument('-m',
                    nargs=2)

args = parser.parse_args()

Read about nargs for how to use multiple arguments for one action.

3 Comments

Thansk Tomerikoo, in my case only one argument can be specified at a time.
In that case @KevinSwindon you can use the first option, and you'll have the extra parameters as a list in additionals.
I went with this option as it's the easiest and most straight forward. I check the params after I call parser.parse_args() as you suggest and this works really well. Thank you Tomerikoo, much appreciated!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.