How to use sub-commands along with optional positional arguments in argparse

424 views Asked by At

Below scripts prints an output as well as opens a webpage based on command line arguments.

#main.py

import os, numpy
import argparse
import webbrowser

new=2

def main():
    parser = argparse.ArgumentParser() 
    parser.add_argument('-i','--input',type=str, help='Choose input')
    parser.add_argument('-d','--display',dest='disp',type=str, help='Opens a webpage', default=None)

    args = parser.parse_args()
 
    if args.input == 'infile':
        print('This is input file')

    if args.disp == 'openbrowser':
        url = "https://stackoverflow.com/"
        webbrowser.open(url,new=new,autoraise=True)
     
if __name__=='__main__':
    main()

If I use the following command:

python3 main.py --input infile --display openbrowser

The desired output is attained. But, I would like --display (ideally without any str) to be parsed along with --input as a sub-command and not as a separate optional flag argument -d. The flag -display is only used if --input is used as the primary flag, and even --display should be optional in itself and shouldn't be obligatory.

So I would like the command line arguments to look like:

python3 main.py --input infile --display

This prints This is input file and opens webpage in the browser. and

python3 main.py --input infile 

This prints the output This is input file only

2

There are 2 answers

1
lwohlhart On BEST ANSWER

You're looking for the action='store_true' property on the argument specification. https://docs.python.org/3/library/argparse.html#action

parser.add_argument('-d', '--display', dest='disp',
                    action='store_true', help='Opens a webpage')
#main.py

import os, numpy
import argparse
import webbrowser

new=2

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-i','--input',type=str, help='Choose input')
    parser.add_argument('-d','--display',dest='disp', action='store_true', help='Opens a webpage')

    args = parser.parse_args()

    if args.input == 'infile':
        print('This is input file')

    if args.disp:
        url = "https://stackoverflow.com/"
        webbrowser.open(url,new=new,autoraise=True)

if __name__=='__main__':
    main()
5
Alexander On

This should be exactly what you are looking for.

In order to add subcommands you use the ArgumentParser.add_subparsers method which requires no parameters and returns an object that can create as many subcommands as you would like.

import os, numpy
import argparse
import webbrowser

new=2

def main():
    parser = argparse.ArgumentParser() 

    subparsers = parser.add_subparsers()
    input_parser = subparsers.add_parser("input")
    input_parser.add_argument('filename', help='path to file')
    args = parser.parse_args()
        input_parser.add_argument(
        '-d',
        '--display',
        dest='disp', 
        action='stor_true',  
        help='Opens a webpage'
     )

    if 'filename' in args:
        print('This is input file')
    if args.disp:
        url = "https://stackoverflow.com/"
        webbrowser.open(url,new=new,autoraise=True)
     
if __name__=='__main__':
    main()